OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
LLUDPServer.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.Collections.Generic;
30 using System.Diagnostics;
31 using System.IO;
32 using System.Net;
33 using System.Net.Sockets;
34 using System.Reflection;
35 using System.Threading;
36 using log4net;
37 using Nini.Config;
38 using OpenMetaverse.Packets;
39 using OpenSim.Framework;
40 using OpenSim.Framework.Console;
41 using OpenSim.Framework.Monitoring;
42 using OpenSim.Region.Framework.Scenes;
43 using OpenSim.Region.Framework.Interfaces;
44 using OpenMetaverse;
45 using Mono.Addins;
47 
48 namespace OpenSim.Region.ClientStack.LindenUDP
49 {
53  [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LLUDPServerShim")]
55  {
56  private bool m_Enabled = true;
57  private IConfigSource m_Config;
58  LLUDPServer m_udpServer;
59 
60  #region INonSharedRegionModule
61  public string Name
62  {
63  get { return "LLUDPServerShim"; }
64  }
65 
66  public Type ReplaceableInterface
67  {
68  get { return null; }
69  }
70 
71  public void Initialise(IConfigSource source)
72  {
73  m_Config = source;
74  }
75 
76  public void Close()
77  {
78  }
79 
80  public void AddRegion(Scene scene)
81  {
82  uint port = (uint)scene.RegionInfo.InternalEndPoint.Port;
83 
84  IPAddress listenIP = scene.RegionInfo.InternalEndPoint.Address;
85  Initialise(listenIP, ref port, scene.RegionInfo.ProxyOffset, scene.RegionInfo.m_allow_alternate_ports, m_Config, scene.AuthenticateHandler);
86  scene.RegionInfo.InternalEndPoint.Port = (int)port;
87 
88  AddScene(scene);
89  }
90 
91  public void RemoveRegion(Scene scene)
92  {
93  Stop();
94  }
95 
96  public void RegionLoaded(Scene scene)
97  {
98  Start();
99  }
100  #endregion
101 
102  public void Initialise(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager)
103  {
104  m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager);
105  }
106 
107  public void AddScene(IScene scene)
108  {
109  m_udpServer.AddScene(scene);
110 
111  StatsManager.RegisterStat(
112  new Stat(
113  "ClientLogoutsDueToNoReceives",
114  "Number of times a client has been logged out because no packets were received before the timeout.",
115  "",
116  "",
117  "clientstack",
118  scene.Name,
119  StatType.Pull,
120  MeasuresOfInterest.None,
121  stat => stat.Value = m_udpServer.ClientLogoutsDueToNoReceives,
122  StatVerbosity.Debug));
123 
124  StatsManager.RegisterStat(
125  new Stat(
126  "IncomingUDPReceivesCount",
127  "Number of UDP receives performed",
128  "",
129  "",
130  "clientstack",
131  scene.Name,
132  StatType.Pull,
133  MeasuresOfInterest.AverageChangeOverTime,
134  stat => stat.Value = m_udpServer.UdpReceives,
135  StatVerbosity.Debug));
136 
137  StatsManager.RegisterStat(
138  new Stat(
139  "IncomingPacketsProcessedCount",
140  "Number of inbound LL protocol packets processed",
141  "",
142  "",
143  "clientstack",
144  scene.Name,
145  StatType.Pull,
146  MeasuresOfInterest.AverageChangeOverTime,
147  stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
148  StatVerbosity.Debug));
149 
150  StatsManager.RegisterStat(
151  new Stat(
152  "IncomingPacketsMalformedCount",
153  "Number of inbound UDP packets that could not be recognized as LL protocol packets.",
154  "",
155  "",
156  "clientstack",
157  scene.Name,
158  StatType.Pull,
159  MeasuresOfInterest.AverageChangeOverTime,
160  stat => stat.Value = m_udpServer.IncomingMalformedPacketCount,
161  StatVerbosity.Info));
162 
163  StatsManager.RegisterStat(
164  new Stat(
165  "IncomingPacketsOrphanedCount",
166  "Number of inbound packets that were not initial connections packets and could not be associated with a viewer.",
167  "",
168  "",
169  "clientstack",
170  scene.Name,
171  StatType.Pull,
172  MeasuresOfInterest.AverageChangeOverTime,
173  stat => stat.Value = m_udpServer.IncomingOrphanedPacketCount,
174  StatVerbosity.Info));
175 
176  StatsManager.RegisterStat(
177  new Stat(
178  "IncomingPacketsResentCount",
179  "Number of inbound packets that clients indicate are resends.",
180  "",
181  "",
182  "clientstack",
183  scene.Name,
184  StatType.Pull,
185  MeasuresOfInterest.AverageChangeOverTime,
186  stat => stat.Value = m_udpServer.IncomingPacketsResentCount,
187  StatVerbosity.Debug));
188 
189  StatsManager.RegisterStat(
190  new Stat(
191  "OutgoingUDPSendsCount",
192  "Number of UDP sends performed",
193  "",
194  "",
195  "clientstack",
196  scene.Name,
197  StatType.Pull,
198  MeasuresOfInterest.AverageChangeOverTime,
199  stat => stat.Value = m_udpServer.UdpSends,
200  StatVerbosity.Debug));
201 
202  StatsManager.RegisterStat(
203  new Stat(
204  "OutgoingPacketsResentCount",
205  "Number of packets resent because a client did not acknowledge receipt",
206  "",
207  "",
208  "clientstack",
209  scene.Name,
210  StatType.Pull,
211  MeasuresOfInterest.AverageChangeOverTime,
212  stat => stat.Value = m_udpServer.PacketsResentCount,
213  StatVerbosity.Debug));
214 
215  StatsManager.RegisterStat(
216  new Stat(
217  "AverageUDPProcessTime",
218  "Average number of milliseconds taken to process each incoming UDP packet in a sample.",
219  "This is for initial receive processing which is separate from the later client LL packet processing stage.",
220  "ms",
221  "clientstack",
222  scene.Name,
223  StatType.Pull,
224  MeasuresOfInterest.None,
225  stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod,
226 // stat =>
227 // stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod, 7),
228  StatVerbosity.Debug));
229  }
230 
231  public bool HandlesRegion(Location x)
232  {
233  return m_udpServer.HandlesRegion(x);
234  }
235 
236  public void Start()
237  {
238  m_udpServer.Start();
239  }
240 
241  public void Stop()
242  {
243  m_udpServer.Stop();
244  }
245 
246  }
247 
253  {
254  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
255 
257  public const int MTU = 1400;
258 
260  public int ClientLogoutsDueToNoReceives { get; private set; }
261 
265  public int DefaultClientPacketDebugLevel { get; set; }
266 
271  public bool DiscardInboundAgentUpdates { get; set; }
272 
274  public readonly float TickCountResolution;
275 
278  public readonly int PrimUpdatesPerCallback;
279 
282  public readonly int TextureSendLimit;
283 
285  //PacketEventDictionary packetEvents = new PacketEventDictionary();
287  //private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
288 
289  private OpenSim.Framework.BlockingQueue<IncomingPacket> packetInbox = new OpenSim.Framework.BlockingQueue<IncomingPacket>();
290 
292  public TokenBucket Throttle { get; private set; }
293 
300  public ThrottleRates ThrottleRates { get; private set; }
301 
303  private AgentCircuitManager m_circuitManager;
304 
306  public Scene Scene { get; private set; }
307 
309  private Location m_location;
310 
314  private int m_recvBufferSize;
315 
317  private bool m_asyncPacketHandling;
318 
321  private bool m_packetSent;
322 
324  private int m_elapsedMSSinceLastStatReport = 0;
325 
327  private int m_tickLastOutgoingPacketHandler;
328 
330  private int m_elapsedMSOutgoingPacketHandler;
331 
333  private int m_elapsed100MSOutgoingPacketHandler;
334 
336  private int m_elapsed500MSOutgoingPacketHandler;
337 
339  protected bool m_resendUnacked;
340 
342  protected bool m_sendAcks;
343 
345  protected bool m_sendPing;
346 
347  private int m_animationSequenceNumber;
348 
349  public int NextAnimationSequenceNumber
350  {
351  get
352  {
353  m_animationSequenceNumber++;
354  if (m_animationSequenceNumber > 2147482624)
355  m_animationSequenceNumber = 1;
356  return m_animationSequenceNumber;
357  }
358  }
359 
360 
361 
362  private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
363 
372 // private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
373 
374  private Pool<IncomingPacket> m_incomingPacketPool;
375 
379  private Stat m_poolCountStat;
380 
384  private Stat m_incomingPacketPoolStat;
385 
386  private int m_defaultRTO = 0;
387  private int m_maxRTO = 0;
388  private int m_ackTimeout = 0;
389  private int m_pausedAckTimeout = 0;
390  private bool m_disableFacelights = false;
391 
392  public Socket Server { get { return null; } }
393 
397  internal int PacketsResentCount { get; set; }
398 
402  internal int PacketsSentCount { get; set; }
403 
407  internal int IncomingPacketsResentCount { get; set; }
408 
412  public int IncomingMalformedPacketCount { get; private set; }
413 
417  public int IncomingOrphanedPacketCount { get; private set; }
418 
422  private IClientAPI m_currentOutgoingClient;
423 
427  private IClientAPI m_currentIncomingClient;
428 
433  public JobEngine IpahEngine { get; private set; }
434 
443  public JobEngine OqrEngine { get; private set; }
444 
445  public LLUDPServer(
446  IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port,
447  IConfigSource configSource, AgentCircuitManager circuitManager)
448  : base(listenIP, (int)port)
449  {
450  #region Environment.TickCount Measurement
451 
452  // Measure the resolution of Environment.TickCount
453  TickCountResolution = 0f;
454  for (int i = 0; i < 10; i++)
455  {
456  int start = Environment.TickCount;
457  int now = start;
458  while (now == start)
459  now = Environment.TickCount;
460  TickCountResolution += (float)(now - start) * 0.1f;
461  }
462  TickCountResolution = (float)Math.Ceiling(TickCountResolution);
463  m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms");
464 
465  #endregion Environment.TickCount Measurement
466 
467  m_circuitManager = circuitManager;
468  int sceneThrottleBps = 0;
469  bool usePools = false;
470 
471 
472 
473  IConfig config = configSource.Configs["ClientStack.LindenUDP"];
474  if (config != null)
475  {
476  m_asyncPacketHandling = config.GetBoolean("async_packet_handling", true);
477  m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0);
478  sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0);
479 
480  PrimUpdatesPerCallback = config.GetInt("PrimUpdatesPerCallback", 100);
481  TextureSendLimit = config.GetInt("TextureSendLimit", 20);
482 
483  m_defaultRTO = config.GetInt("DefaultRTO", 0);
484  m_maxRTO = config.GetInt("MaxRTO", 0);
485  m_disableFacelights = config.GetBoolean("DisableFacelights", false);
486  m_ackTimeout = 1000 * config.GetInt("AckTimeout", 60);
487  m_pausedAckTimeout = 1000 * config.GetInt("PausedAckTimeout", 300);
488  }
489  else
490  {
491  PrimUpdatesPerCallback = 100;
492  TextureSendLimit = 20;
493  m_ackTimeout = 1000 * 60; // 1 minute
494  m_pausedAckTimeout = 1000 * 300; // 5 minutes
495  }
496 
497  // FIXME: This actually only needs to be done once since the PacketPool is shared across all servers.
498  // However, there is no harm in temporarily doing it multiple times.
499  IConfig packetConfig = configSource.Configs["PacketPool"];
500  if (packetConfig != null)
501  {
502  PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true);
503  PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true);
504  usePools = packetConfig.GetBoolean("RecycleBaseUDPPackets", usePools);
505  }
506 
507  #region BinaryStats
508  config = configSource.Configs["Statistics.Binary"];
509  m_shouldCollectStats = false;
510  if (config != null)
511  {
512  m_shouldCollectStats = config.GetBoolean("Enabled", false);
513  binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt("packet_headers_period_seconds", 300));
514  binStatsDir = config.GetString("stats_dir", ".");
515  m_aggregatedBWStats = config.GetBoolean("aggregatedBWStats", false);
516  }
517  #endregion BinaryStats
518 
519  Throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps * 10e-3f);
520  ThrottleRates = new ThrottleRates(configSource);
521 
522  Random rnd = new Random(Util.EnvironmentTickCount());
523  m_animationSequenceNumber = rnd.Next(11474826);
524 
525 // if (usePools)
526 // EnablePools();
527  DisablePools();
528  }
529 
530  public void Start()
531  {
532  StartInbound();
533  StartOutbound();
534  IpahEngine.Start();
535  OqrEngine.Start();
536 
537  m_elapsedMSSinceLastStatReport = Environment.TickCount;
538  }
539 
540  public void StartInbound()
541  {
542  m_log.InfoFormat(
543  "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}",
544  m_asyncPacketHandling ? "asynchronous" : "synchronous", UsePools);
545 
546  base.StartInbound(m_recvBufferSize, m_asyncPacketHandling);
547 
548  // This thread will process the packets received that are placed on the packetInbox
549  WorkManager.StartThread(
550  IncomingPacketHandler,
551  string.Format("Incoming Packets ({0})", Scene.Name),
552  ThreadPriority.Normal,
553  false,
554  true,
555  GetWatchdogIncomingAlarmData,
556  Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
557  }
558 
559  public override void StartOutbound()
560  {
561  m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server");
562 
563  base.StartOutbound();
564 
565  WorkManager.StartThread(
566  OutgoingPacketHandler,
567  string.Format("Outgoing Packets ({0})", Scene.Name),
568  ThreadPriority.Normal,
569  false,
570  true,
571  GetWatchdogOutgoingAlarmData,
572  Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
573  }
574 
575  public void Stop()
576  {
577  m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + Scene.Name);
578  base.StopOutbound();
579  base.StopInbound();
580  IpahEngine.Stop();
581  OqrEngine.Stop();
582  }
583 
584  public override bool EnablePools()
585  {
586  if (!UsePools)
587  {
588  base.EnablePools();
589 
590  m_incomingPacketPool = new Pool<IncomingPacket>(() => new IncomingPacket(), 500);
591 
592  return true;
593  }
594 
595  return false;
596  }
597 
598  public override bool DisablePools()
599  {
600  if (UsePools)
601  {
602  base.DisablePools();
603 
604  StatsManager.DeregisterStat(m_incomingPacketPoolStat);
605 
606  // We won't null out the pool to avoid a race condition with code that may be in the middle of using it.
607 
608  return true;
609  }
610 
611  return false;
612  }
613 
618  protected internal void EnablePoolStats()
619  {
620  m_poolCountStat
621  = new Stat(
622  "UDPPacketBufferPoolCount",
623  "Objects within the UDPPacketBuffer pool",
624  "The number of objects currently stored within the UDPPacketBuffer pool",
625  "",
626  "clientstack",
627  Scene.Name,
628  StatType.Pull,
629  stat => stat.Value = Pool.Count,
630  StatVerbosity.Debug);
631 
632  StatsManager.RegisterStat(m_poolCountStat);
633 
634  m_incomingPacketPoolStat
635  = new Stat(
636  "IncomingPacketPoolCount",
637  "Objects within incoming packet pool",
638  "The number of objects currently stored within the incoming packet pool",
639  "",
640  "clientstack",
641  Scene.Name,
642  StatType.Pull,
643  stat => stat.Value = m_incomingPacketPool.Count,
644  StatVerbosity.Debug);
645 
646  StatsManager.RegisterStat(m_incomingPacketPoolStat);
647  }
648 
652  protected internal void DisablePoolStats()
653  {
654  StatsManager.DeregisterStat(m_poolCountStat);
655  m_poolCountStat = null;
656 
657  StatsManager.DeregisterStat(m_incomingPacketPoolStat);
658  m_incomingPacketPoolStat = null;
659  }
660 
665  private string GetWatchdogIncomingAlarmData()
666  {
667  return string.Format(
668  "Client is {0}",
669  m_currentIncomingClient != null ? m_currentIncomingClient.Name : "none");
670  }
671 
676  private string GetWatchdogOutgoingAlarmData()
677  {
678  return string.Format(
679  "Client is {0}",
680  m_currentOutgoingClient != null ? m_currentOutgoingClient.Name : "none");
681  }
682 
683  public void AddScene(IScene scene)
684  {
685  if (Scene != null)
686  {
687  m_log.Error("[LLUDPSERVER]: AddScene() called on an LLUDPServer that already has a scene");
688  return;
689  }
690 
691  if (!(scene is Scene))
692  {
693  m_log.Error("[LLUDPSERVER]: AddScene() called with an unrecognized scene type " + scene.GetType());
694  return;
695  }
696 
697  Scene = (Scene)scene;
698  m_location = new Location(Scene.RegionInfo.RegionHandle);
699 
700  IpahEngine
701  = new JobEngine(
702  string.Format("Incoming Packet Async Handling Engine ({0})", Scene.Name),
703  "INCOMING PACKET ASYNC HANDLING ENGINE");
704 
705  OqrEngine
706  = new JobEngine(
707  string.Format("Outgoing Queue Refill Engine ({0})", Scene.Name),
708  "OUTGOING QUEUE REFILL ENGINE");
709 
710  StatsManager.RegisterStat(
711  new Stat(
712  "InboxPacketsCount",
713  "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
714  "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
715  "",
716  "clientstack",
717  scene.Name,
718  StatType.Pull,
719  MeasuresOfInterest.AverageChangeOverTime,
720  stat => stat.Value = packetInbox.Count(),
721  StatVerbosity.Debug));
722 
723  // XXX: These stats are also pool stats but we register them separately since they are currently not
724  // turned on and off by EnablePools()/DisablePools()
725  StatsManager.RegisterStat(
726  new PercentageStat(
727  "PacketsReused",
728  "Packets reused",
729  "Number of packets reused out of all requests to the packet pool",
730  "clientstack",
731  Scene.Name,
732  StatType.Pull,
733  stat =>
734  { PercentageStat pstat = (PercentageStat)stat;
736  pstat.Antecedent = PacketPool.Instance.PacketsReused; },
737  StatVerbosity.Debug));
738 
739  StatsManager.RegisterStat(
740  new PercentageStat(
741  "PacketDataBlocksReused",
742  "Packet data blocks reused",
743  "Number of data blocks reused out of all requests to the packet pool",
744  "clientstack",
745  Scene.Name,
746  StatType.Pull,
747  stat =>
748  { PercentageStat pstat = (PercentageStat)stat;
750  pstat.Antecedent = PacketPool.Instance.BlocksReused; },
751  StatVerbosity.Debug));
752 
753  StatsManager.RegisterStat(
754  new Stat(
755  "PacketsPoolCount",
756  "Objects within the packet pool",
757  "The number of objects currently stored within the packet pool",
758  "",
759  "clientstack",
760  Scene.Name,
761  StatType.Pull,
762  stat => stat.Value = PacketPool.Instance.PacketsPooled,
763  StatVerbosity.Debug));
764 
765  StatsManager.RegisterStat(
766  new Stat(
767  "PacketDataBlocksPoolCount",
768  "Objects within the packet data block pool",
769  "The number of objects currently stored within the packet data block pool",
770  "",
771  "clientstack",
772  Scene.Name,
773  StatType.Pull,
774  stat => stat.Value = PacketPool.Instance.BlocksPooled,
775  StatVerbosity.Debug));
776 
777  StatsManager.RegisterStat(
778  new Stat(
779  "OutgoingPacketsQueuedCount",
780  "Packets queued for outgoing send",
781  "Number of queued outgoing packets across all connections",
782  "",
783  "clientstack",
784  Scene.Name,
785  StatType.Pull,
786  MeasuresOfInterest.AverageChangeOverTime,
787  stat => stat.Value = GetTotalQueuedOutgoingPackets(),
788  StatVerbosity.Info));
789 
790  StatsManager.RegisterStat(
791  new Stat(
792  "IncomingPacketAsyncRequestsWaiting",
793  "Number of incoming packets waiting for async processing in engine.",
794  "",
795  "",
796  "clientstack",
797  Scene.Name,
798  StatType.Pull,
799  MeasuresOfInterest.None,
800  stat => stat.Value = IpahEngine.JobsWaiting,
801  StatVerbosity.Debug));
802 
803  StatsManager.RegisterStat(
804  new Stat(
805  "OQRERequestsWaiting",
806  "Number of outgong queue refill requests waiting for processing.",
807  "",
808  "",
809  "clientstack",
810  Scene.Name,
811  StatType.Pull,
812  MeasuresOfInterest.None,
813  stat => stat.Value = OqrEngine.JobsWaiting,
814  StatVerbosity.Debug));
815 
816  // We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by
817  // scene name
818  if (UsePools)
819  EnablePoolStats();
820 
821 
822  LLUDPServerCommands commands = new LLUDPServerCommands(MainConsole.Instance, this);
823  commands.Register();
824 
825  }
826 
827  public bool HandlesRegion(Location x)
828  {
829  return x == m_location;
830  }
831 
833  {
834  int total = 0;
835 
836  foreach (ScenePresence sp in Scene.GetScenePresences())
837  {
838  // XXX: Need a better way to determine which IClientAPIs have UDPClients (NPCs do not, for instance).
840  {
841  LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
842  total += udpClient.GetTotalPacketsQueuedCount();
843  }
844  }
845 
846  return total;
847  }
848 
849 // public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting)
850 // {
851 // // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way
852 // if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting)
853 // allowSplitting = false;
854 //
855 // if (allowSplitting && packet.HasVariableBlocks)
856 // {
857 // byte[][] datas = packet.ToBytesMultiple();
858 // int packetCount = datas.Length;
859 //
860 // if (packetCount < 1)
861 // m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length);
862 //
863 // for (int i = 0; i < packetCount; i++)
864 // {
865 // byte[] data = datas[i];
866 // m_scene.ForEachClient(
867 // delegate(IClientAPI client)
868 // {
869 // if (client is LLClientView)
870 // SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
871 // }
872 // );
873 // }
874 // }
875 // else
876 // {
877 // byte[] data = packet.ToBytes();
878 // m_scene.ForEachClient(
879 // delegate(IClientAPI client)
880 // {
881 // if (client is LLClientView)
882 // SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
883 // }
884 // );
885 // }
886 // }
887 
899  public virtual void SendPacket(
900  LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting, UnackedPacketMethod method)
901  {
902  // CoarseLocationUpdate packets cannot be split in an automated way
903  if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
904  allowSplitting = false;
905 
906  bool packetQueued = false;
907 
908  if (allowSplitting && packet.HasVariableBlocks)
909  {
910  byte[][] datas = packet.ToBytesMultiple();
911  int packetCount = datas.Length;
912 
913  if (packetCount < 1)
914  m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length);
915 
916  for (int i = 0; i < packetCount; i++)
917  {
918  byte[] data = datas[i];
919  if (!SendPacketData(udpClient, data, packet.Type, category, method))
920  packetQueued = true;
921  }
922  }
923  else
924  {
925  byte[] data = packet.ToBytes();
926  if (!SendPacketData(udpClient, data, packet.Type, category, method))
927  packetQueued = true;
928  }
929 
930  PacketPool.Instance.ReturnPacket(packet);
931 
933 // if (packetQueued)
934 // m_dataPresentEvent.Set();
935  }
936 
949  public bool SendPacketData(
950  LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method)
951  {
952  int dataLength = data.Length;
953  bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0;
954  bool doCopy = true;
955 
956  // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum.
957  // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting
958  // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here
959  // to accomodate for both common scenarios and provide ample room for ACK appending in both
960  int bufferSize = (dataLength > 180) ? LLUDPServer.MTU : 200;
961 
962  UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize);
963 
964  // Zerocode if needed
965  if (doZerocode)
966  {
967  try
968  {
969  dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data);
970  doCopy = false;
971  }
972  catch (IndexOutOfRangeException)
973  {
974  // The packet grew larger than the bufferSize while zerocoding.
975  // Remove the MSG_ZEROCODED flag and send the unencoded data
976  // instead
977  m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". DataLength=" + dataLength +
978  " and BufferLength=" + buffer.Data.Length + ". Removing MSG_ZEROCODED flag");
979  data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED);
980  }
981  }
982 
983  // If the packet data wasn't already copied during zerocoding, copy it now
984  if (doCopy)
985  {
986  if (dataLength <= buffer.Data.Length)
987  {
988  Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
989  }
990  else
991  {
992  bufferSize = dataLength;
993  buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize);
994 
995  m_log.Error("[LLUDPSERVER]: Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" +
996  type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length);
997  Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
998  }
999  }
1000 
1001  buffer.DataLength = dataLength;
1002 
1003  #region Queue or Send
1004 
1005  bool highPriority = false;
1006 
1007  if (category != ThrottleOutPacketType.Unknown && (category & ThrottleOutPacketType.HighPriority) != 0)
1008  {
1009  category = (ThrottleOutPacketType)((int)category & 127);
1010  highPriority = true;
1011  }
1012 
1013  OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null);
1014 
1015  // If we were not provided a method for handling unacked, use the UDPServer default method
1016  if ((outgoingPacket.Buffer.Data[0] & Helpers.MSG_RELIABLE) != 0)
1017  outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method);
1018 
1019  // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will
1020  // continue to display the deleted object until relog. Therefore, we need to always queue a kill object
1021  // packet so that it isn't sent before a queued update packet.
1022 
1023  bool requestQueue = type == PacketType.KillObject;
1024  if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority))
1025  {
1026  SendPacketFinal(outgoingPacket);
1027  return true;
1028  }
1029 
1030  return false;
1031 
1032  #endregion Queue or Send
1033  }
1034 
1035  public void SendAcks(LLUDPClient udpClient)
1036  {
1037  uint ack;
1038 
1039  if (udpClient.PendingAcks.Dequeue(out ack))
1040  {
1041  List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>();
1042  PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock();
1043  block.ID = ack;
1044  blocks.Add(block);
1045 
1046  while (udpClient.PendingAcks.Dequeue(out ack))
1047  {
1048  block = new PacketAckPacket.PacketsBlock();
1049  block.ID = ack;
1050  blocks.Add(block);
1051  }
1052 
1053  PacketAckPacket packet = new PacketAckPacket();
1054  packet.Header.Reliable = false;
1055  packet.Packets = blocks.ToArray();
1056 
1057  SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true, null);
1058  }
1059  }
1060 
1061  public void SendPing(LLUDPClient udpClient)
1062  {
1063  StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck);
1064  pc.Header.Reliable = false;
1065 
1066  pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++;
1067  // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit
1068  pc.PingID.OldestUnacked = 0;
1069 
1070  SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null);
1071  udpClient.m_lastStartpingTimeMS = Util.EnvironmentTickCount();
1072  }
1073 
1074  public void CompletePing(LLUDPClient udpClient, byte pingID)
1075  {
1076  CompletePingCheckPacket completePing = new CompletePingCheckPacket();
1077  completePing.PingID.PingID = pingID;
1078  SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false, null);
1079  }
1080 
1081  public void HandleUnacked(LLClientView client)
1082  {
1083  LLUDPClient udpClient = client.UDPClient;
1084 
1085  if (!udpClient.IsConnected)
1086  return;
1087 
1088  // Disconnect an agent if no packets are received for some time
1089  int timeoutTicks = m_ackTimeout;
1090 
1091  // Allow more slack if the client is "paused" eg file upload dialogue is open
1092  // Some sort of limit is needed in case the client crashes, loses its network connection
1093  // or some other disaster prevents it from sendung the AgentResume
1094  if (udpClient.IsPaused)
1095  timeoutTicks = m_pausedAckTimeout;
1096 
1097  if (client.IsActive &&
1098  (Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > timeoutTicks)
1099  {
1100  // We must set IsActive synchronously so that we can stop the packet loop reinvoking this method, even
1101  // though it's set later on by LLClientView.Close()
1102  client.IsActive = false;
1103 
1104  // Fire this out on a different thread so that we don't hold up outgoing packet processing for
1105  // everybody else if this is being called due to an ack timeout.
1106  // This is the same as processing as the async process of a logout request.
1107  Util.FireAndForget(
1108  o => DeactivateClientDueToTimeout(client, timeoutTicks), null, "LLUDPServer.DeactivateClientDueToTimeout");
1109 
1110  return;
1111  }
1112 
1113  // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO
1114  List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO);
1115 
1116  if (expiredPackets != null)
1117  {
1118  //m_log.Debug("[LLUDPSERVER]: Handling " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO);
1119  // Exponential backoff of the retransmission timeout
1120  udpClient.BackoffRTO();
1121  for (int i = 0; i < expiredPackets.Count; ++i)
1122  expiredPackets[i].UnackedMethod(expiredPackets[i]);
1123  }
1124  }
1125 
1126  public void ResendUnacked(OutgoingPacket outgoingPacket)
1127  {
1128  //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
1129  // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
1130 
1131  // Set the resent flag
1132  outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
1133  outgoingPacket.Category = ThrottleOutPacketType.Resend;
1134 
1135  // Bump up the resend count on this packet
1136  Interlocked.Increment(ref outgoingPacket.ResendCount);
1137 
1138  // Requeue or resend the packet
1139  if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, false))
1140  SendPacketFinal(outgoingPacket);
1141  }
1142 
1143  public void Flush(LLUDPClient udpClient)
1144  {
1145  // FIXME: Implement?
1146  }
1147 
1152  internal void SendPacketFinal(OutgoingPacket outgoingPacket)
1153  {
1154  UDPPacketBuffer buffer = outgoingPacket.Buffer;
1155  byte flags = buffer.Data[0];
1156  bool isResend = (flags & Helpers.MSG_RESENT) != 0;
1157  bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0;
1158  bool isZerocoded = (flags & Helpers.MSG_ZEROCODED) != 0;
1159  LLUDPClient udpClient = outgoingPacket.Client;
1160 
1161  if (!udpClient.IsConnected)
1162  return;
1163 
1164  #region ACK Appending
1165 
1166  int dataLength = buffer.DataLength;
1167 
1168  // NOTE: I'm seeing problems with some viewers when ACKs are appended to zerocoded packets so I've disabled that here
1169  if (!isZerocoded && !isResend && outgoingPacket.UnackedMethod == null)
1170  {
1171  // Keep appending ACKs until there is no room left in the buffer or there are
1172  // no more ACKs to append
1173  uint ackCount = 0;
1174  uint ack;
1175  while (dataLength + 5 < buffer.Data.Length && udpClient.PendingAcks.Dequeue(out ack))
1176  {
1177  Utils.UIntToBytesBig(ack, buffer.Data, dataLength);
1178  dataLength += 4;
1179  ++ackCount;
1180  }
1181 
1182  if (ackCount > 0)
1183  {
1184  // Set the last byte of the packet equal to the number of appended ACKs
1185  buffer.Data[dataLength++] = (byte)ackCount;
1186  // Set the appended ACKs flag on this packet
1187  buffer.Data[0] = (byte)(buffer.Data[0] | Helpers.MSG_APPENDED_ACKS);
1188  }
1189  }
1190 
1191  buffer.DataLength = dataLength;
1192 
1193  #endregion ACK Appending
1194 
1195  #region Sequence Number Assignment
1196 
1197  if (!isResend)
1198  {
1199  // Not a resend, assign a new sequence number
1200  uint sequenceNumber = (uint)Interlocked.Increment(ref udpClient.CurrentSequence);
1201  Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1);
1202  outgoingPacket.SequenceNumber = sequenceNumber;
1203 
1204  if (isReliable)
1205  {
1206  // Add this packet to the list of ACK responses we are waiting on from the server
1207  udpClient.NeedAcks.Add(outgoingPacket);
1208  }
1209  }
1210  else
1211  {
1212  Interlocked.Increment(ref udpClient.PacketsResent);
1213 
1214  // We're not going to worry about interlock yet since its not currently critical that this total count
1215  // is 100% correct
1216  PacketsResentCount++;
1217  }
1218 
1219  #endregion Sequence Number Assignment
1220 
1221  // Stats tracking
1222  Interlocked.Increment(ref udpClient.PacketsSent);
1223 
1224  // We're not going to worry about interlock yet since its not currently critical that this total count
1225  // is 100% correct
1226  PacketsSentCount++;
1227 
1228  if (udpClient.DebugDataOutLevel > 0)
1229  m_log.DebugFormat(
1230  "[LLUDPSERVER]: Sending packet #{0} (rel: {1}, res: {2}) to {3} from {4}",
1231  outgoingPacket.SequenceNumber, isReliable, isResend, udpClient.AgentID, Scene.Name);
1232 
1233  // Put the UDP payload on the wire
1234  AsyncBeginSend(buffer);
1235 
1236  // Keep track of when this packet was sent out (right now)
1237  outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue;
1238  }
1239 
1240  private void RecordMalformedInboundPacket(IPEndPoint endPoint)
1241  {
1242 // if (m_malformedCount < 100)
1243 // m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
1244 
1245  IncomingMalformedPacketCount++;
1246 
1247  if ((IncomingMalformedPacketCount % 10000) == 0)
1248  m_log.WarnFormat(
1249  "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}",
1250  IncomingMalformedPacketCount, endPoint);
1251  }
1252 
1253  public override void PacketReceived(UDPPacketBuffer buffer)
1254  {
1255  // Debugging/Profiling
1256  //try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; }
1257  //catch (Exception) { }
1258 // m_log.DebugFormat(
1259 // "[LLUDPSERVER]: Packet received from {0} in {1}", buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1260 
1261  LLUDPClient udpClient = null;
1262  Packet packet = null;
1263  int packetEnd = buffer.DataLength - 1;
1264  IPEndPoint endPoint = (IPEndPoint)buffer.RemoteEndPoint;
1265 
1266  #region Decoding
1267 
1268  if (buffer.DataLength < 7)
1269  {
1270 // m_log.WarnFormat(
1271 // "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
1272 // buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1273 
1274  RecordMalformedInboundPacket(endPoint);
1275 
1276  return; // Drop undersized packet
1277  }
1278 
1279  int headerLen = 7;
1280  if (buffer.Data[6] == 0xFF)
1281  {
1282  if (buffer.Data[7] == 0xFF)
1283  headerLen = 10;
1284  else
1285  headerLen = 8;
1286  }
1287 
1288  if (buffer.DataLength < headerLen)
1289  {
1290 // m_log.WarnFormat(
1291 // "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}",
1292 // buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
1293 
1294  RecordMalformedInboundPacket(endPoint);
1295 
1296  return; // Malformed header
1297  }
1298 
1299  try
1300  {
1301 // packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
1302 // // Only allocate a buffer for zerodecoding if the packet is zerocoded
1303 // ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
1304  // If OpenSimUDPBase.UsePool == true (which is currently separate from the PacketPool) then we
1305  // assume that packet construction does not retain a reference to byte[] buffer.Data (instead, all
1306  // bytes are copied out).
1307  packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd,
1308  // Only allocate a buffer for zerodecoding if the packet is zerocoded
1309  ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
1310  }
1311  catch (Exception e)
1312  {
1313  if (IncomingMalformedPacketCount < 100)
1314  m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
1315  }
1316 
1317  // Fail-safe check
1318  if (packet == null)
1319  {
1320  if (IncomingMalformedPacketCount < 100)
1321  {
1322  m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data {2}:",
1323  buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
1324  }
1325 
1326  RecordMalformedInboundPacket(endPoint);
1327 
1328  return;
1329  }
1330 
1331  #endregion Decoding
1332 
1333  #region Packet to Client Mapping
1334 
1335  // If there is already a client for this endpoint, don't process UseCircuitCode
1336  IClientAPI client = null;
1337  if (!Scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1338  {
1339  // UseCircuitCode handling
1340  if (packet.Type == PacketType.UseCircuitCode)
1341  {
1342  // And if there is a UseCircuitCode pending, also drop it
1343  lock (m_pendingCache)
1344  {
1345  if (m_pendingCache.Contains(endPoint))
1346  return;
1347 
1348  m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60);
1349  }
1350 
1351  // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1352  // buffer.
1353  object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1354 
1355  Util.FireAndForget(HandleUseCircuitCode, array);
1356 
1357  return;
1358  }
1359  }
1360 
1361  // If this is a pending connection, enqueue, don't process yet
1362  lock (m_pendingCache)
1363  {
1364  Queue<UDPPacketBuffer> queue;
1365  if (m_pendingCache.TryGetValue(endPoint, out queue))
1366  {
1367  //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type);
1368  queue.Enqueue(buffer);
1369  return;
1370  }
1371 
1372 /*
1373  else if (packet.Type == PacketType.CompleteAgentMovement)
1374  {
1375  // Send ack straight away to let the viewer know that we got it.
1376  SendAckImmediate(endPoint, packet.Header.Sequence);
1377 
1378  // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1379  // buffer.
1380  object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1381 
1382  Util.FireAndForget(HandleCompleteMovementIntoRegion, array);
1383 
1384  return;
1385  }
1386  */
1387  }
1388 
1389  // Determine which agent this packet came from
1390  if (client == null || !(client is LLClientView))
1391  {
1392  //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1393 
1394  IncomingOrphanedPacketCount++;
1395 
1396  if ((IncomingOrphanedPacketCount % 10000) == 0)
1397  m_log.WarnFormat(
1398  "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}",
1399  IncomingOrphanedPacketCount, endPoint);
1400 
1401  return;
1402  }
1403 
1404  udpClient = ((LLClientView)client).UDPClient;
1405 
1406  if (!udpClient.IsConnected)
1407  {
1408  m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + Scene.RegionInfo.RegionName);
1409  return;
1410  }
1411 
1412  #endregion Packet to Client Mapping
1413 
1414  // Stats tracking
1415  Interlocked.Increment(ref udpClient.PacketsReceived);
1416 
1417  int now = Environment.TickCount & Int32.MaxValue;
1418  udpClient.TickLastPacketReceived = now;
1419 
1420  #region ACK Receiving
1421 
1422  // Handle appended ACKs
1423  if (packet.Header.AppendedAcks && packet.Header.AckList != null)
1424  {
1425  // m_log.DebugFormat(
1426  // "[LLUDPSERVER]: Handling {0} appended acks from {1} in {2}",
1427  // packet.Header.AckList.Length, client.Name, m_scene.Name);
1428 
1429  for (int i = 0; i < packet.Header.AckList.Length; i++)
1430  udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent);
1431  }
1432 
1433  // Handle PacketAck packets
1434  if (packet.Type == PacketType.PacketAck)
1435  {
1436  PacketAckPacket ackPacket = (PacketAckPacket)packet;
1437 
1438  // m_log.DebugFormat(
1439  // "[LLUDPSERVER]: Handling {0} packet acks for {1} in {2}",
1440  // ackPacket.Packets.Length, client.Name, m_scene.Name);
1441 
1442  for (int i = 0; i < ackPacket.Packets.Length; i++)
1443  udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent);
1444 
1445  // We don't need to do anything else with PacketAck packets
1446  return;
1447  }
1448 
1449  #endregion ACK Receiving
1450 
1451  #region ACK Sending
1452 
1453  if (packet.Header.Reliable)
1454  {
1455 // m_log.DebugFormat(
1456 // "[LLUDPSERVER]: Adding ack request for {0} {1} from {2} in {3}",
1457 // packet.Type, packet.Header.Sequence, client.Name, m_scene.Name);
1458 
1459  udpClient.PendingAcks.Enqueue(packet.Header.Sequence);
1460 
1461  // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
1462  // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove
1463  // 2*MTU bytes from the value and send ACKs, and finally add the local value back to
1464  // client.BytesSinceLastACK. Lockless thread safety
1465  int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0);
1466  bytesSinceLastACK += buffer.DataLength;
1467  if (bytesSinceLastACK > LLUDPServer.MTU * 2)
1468  {
1469  bytesSinceLastACK -= LLUDPServer.MTU * 2;
1470  SendAcks(udpClient);
1471  }
1472  Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK);
1473  }
1474 
1475  #endregion ACK Sending
1476 
1477  #region Incoming Packet Accounting
1478 
1479  // We're not going to worry about interlock yet since its not currently critical that this total count
1480  // is 100% correct
1481  if (packet.Header.Resent)
1482  IncomingPacketsResentCount++;
1483 
1484  // Check the archive of received reliable packet IDs to see whether we already received this packet
1485  if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence))
1486  {
1487  if (packet.Header.Resent)
1488  m_log.DebugFormat(
1489  "[LLUDPSERVER]: Received a resend of already processed packet #{0}, type {1} from {2}",
1490  packet.Header.Sequence, packet.Type, client.Name);
1491  else
1492  m_log.WarnFormat(
1493  "[LLUDPSERVER]: Received a duplicate (not marked as resend) of packet #{0}, type {1} from {2}",
1494  packet.Header.Sequence, packet.Type, client.Name);
1495 
1496  // Avoid firing a callback twice for the same packet
1497  return;
1498  }
1499 
1500  #endregion Incoming Packet Accounting
1501 
1502  #region BinaryStats
1503  LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
1504  #endregion BinaryStats
1505 
1506 
1507 //AgentUpdate removed from here
1508 
1509 
1510  #region Ping Check Handling
1511 
1512  if (packet.Type == PacketType.StartPingCheck)
1513  {
1514 // m_log.DebugFormat("[LLUDPSERVER]: Handling ping from {0} in {1}", client.Name, m_scene.Name);
1515 
1516  // We don't need to do anything else with ping checks
1517  StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
1518  CompletePing(udpClient, startPing.PingID.PingID);
1519 
1520  if ((Environment.TickCount - m_elapsedMSSinceLastStatReport) >= 3000)
1521  {
1522  udpClient.SendPacketStats();
1523  m_elapsedMSSinceLastStatReport = Environment.TickCount;
1524  }
1525  return;
1526  }
1527  else if (packet.Type == PacketType.CompletePingCheck)
1528  {
1529  int t = Util.EnvironmentTickCountSubtract(udpClient.m_lastStartpingTimeMS);
1530  int c = udpClient.m_pingMS;
1531  c = 800 * c + 200 * t;
1532  c /= 1000;
1533  udpClient.m_pingMS = c;
1534  return;
1535  }
1536 
1537  #endregion Ping Check Handling
1538 
1539  IncomingPacket incomingPacket;
1540 
1541  // Inbox insertion
1542  if (UsePools)
1543  {
1544  incomingPacket = m_incomingPacketPool.GetObject();
1545  incomingPacket.Client = (LLClientView)client;
1546  incomingPacket.Packet = packet;
1547  }
1548  else
1549  {
1550  incomingPacket = new IncomingPacket((LLClientView)client, packet);
1551  }
1552 
1553 // if (incomingPacket.Packet.Type == PacketType.AgentUpdate ||
1554 // incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1555  if (incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1556  packetInbox.PriorityEnqueue(incomingPacket);
1557  else
1558  packetInbox.Enqueue(incomingPacket);
1559 
1560  }
1561 
1562  #region BinaryStats
1563 
1564  public class PacketLogger
1565  {
1566  public DateTime StartTime;
1567  public string Path = null;
1568  public System.IO.BinaryWriter Log = null;
1569  }
1570 
1571  public static PacketLogger PacketLog;
1572 
1573  protected static bool m_shouldCollectStats = false;
1574  // Number of seconds to log for
1575  static TimeSpan binStatsMaxFilesize = TimeSpan.FromSeconds(300);
1576  static object binStatsLogLock = new object();
1577  static string binStatsDir = "";
1578 
1579  //for Aggregated In/Out BW logging
1580  static bool m_aggregatedBWStats = false;
1581  static long m_aggregatedBytesIn = 0;
1582  static long m_aggregatedByestOut = 0;
1583  static object aggBWStatsLock = new object();
1584 
1585  public static long AggregatedLLUDPBytesIn
1586  {
1587  get { return m_aggregatedBytesIn; }
1588  }
1589  public static long AggregatedLLUDPBytesOut
1590  {
1591  get {return m_aggregatedByestOut;}
1592  }
1593 
1594  public static void LogPacketHeader(bool incoming, uint circuit, byte flags, PacketType packetType, ushort size)
1595  {
1596  if (m_aggregatedBWStats)
1597  {
1598  lock (aggBWStatsLock)
1599  {
1600  if (incoming)
1601  m_aggregatedBytesIn += size;
1602  else
1603  m_aggregatedByestOut += size;
1604  }
1605  }
1606 
1607  if (!m_shouldCollectStats) return;
1608 
1609  // Binary logging format is TTTTTTTTCCCCFPPPSS, T=Time, C=Circuit, F=Flags, P=PacketType, S=size
1610 
1611  // Put the incoming bit into the least significant bit of the flags byte
1612  if (incoming)
1613  flags |= 0x01;
1614  else
1615  flags &= 0xFE;
1616 
1617  // Put the flags byte into the most significant bits of the type integer
1618  uint type = (uint)packetType;
1619  type |= (uint)flags << 24;
1620 
1621  // m_log.Debug("1 LogPacketHeader(): Outside lock");
1622  lock (binStatsLogLock)
1623  {
1624  DateTime now = DateTime.Now;
1625 
1626  // m_log.Debug("2 LogPacketHeader(): Inside lock. now is " + now.Ticks);
1627  try
1628  {
1629  if (PacketLog == null || (now > PacketLog.StartTime + binStatsMaxFilesize))
1630  {
1631  if (PacketLog != null && PacketLog.Log != null)
1632  {
1633  PacketLog.Log.Close();
1634  }
1635 
1636  // First log file or time has expired, start writing to a new log file
1637  PacketLog = new PacketLogger();
1638  PacketLog.StartTime = now;
1639  PacketLog.Path = (binStatsDir.Length > 0 ? binStatsDir + System.IO.Path.DirectorySeparatorChar.ToString() : "")
1640  + String.Format("packets-{0}.log", now.ToString("yyyyMMddHHmmss"));
1641  PacketLog.Log = new BinaryWriter(File.Open(PacketLog.Path, FileMode.Append, FileAccess.Write));
1642  }
1643 
1644  // Serialize the data
1645  byte[] output = new byte[18];
1646  Buffer.BlockCopy(BitConverter.GetBytes(now.Ticks), 0, output, 0, 8);
1647  Buffer.BlockCopy(BitConverter.GetBytes(circuit), 0, output, 8, 4);
1648  Buffer.BlockCopy(BitConverter.GetBytes(type), 0, output, 12, 4);
1649  Buffer.BlockCopy(BitConverter.GetBytes(size), 0, output, 16, 2);
1650 
1651  // Write the serialized data to disk
1652  if (PacketLog != null && PacketLog.Log != null)
1653  PacketLog.Log.Write(output);
1654  }
1655  catch (Exception ex)
1656  {
1657  m_log.Error("Packet statistics gathering failed: " + ex.Message, ex);
1658  if (PacketLog.Log != null)
1659  {
1660  PacketLog.Log.Close();
1661  }
1662  PacketLog = null;
1663  }
1664  }
1665  }
1666 
1667  #endregion BinaryStats
1668 
1669  private void HandleUseCircuitCode(object o)
1670  {
1671  IPEndPoint endPoint = null;
1672  IClientAPI client = null;
1673 
1674  try
1675  {
1676 // DateTime startTime = DateTime.Now;
1677  object[] array = (object[])o;
1678  endPoint = (IPEndPoint)array[0];
1679  UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
1680 
1681  m_log.DebugFormat(
1682  "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}",
1683  uccp.CircuitCode.Code, Scene.RegionInfo.RegionName, endPoint);
1684 
1685  AuthenticateResponse sessionInfo;
1686  if (IsClientAuthorized(uccp, out sessionInfo))
1687  {
1688  AgentCircuitData aCircuit = Scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
1689 
1690  // Begin the process of adding the client to the simulator
1691  client
1692  = AddClient(
1693  uccp.CircuitCode.Code,
1694  uccp.CircuitCode.ID,
1695  uccp.CircuitCode.SessionID,
1696  endPoint,
1697  sessionInfo);
1698 
1699  // This will be true if the client is new, e.g. not
1700  // an existing child agent, and there is no circuit data
1701  if (client != null && aCircuit == null)
1702  {
1703  Scene.CloseAgent(client.AgentId, true);
1704  return;
1705  }
1706 
1707  // Now we know we can handle more data
1708  Thread.Sleep(200);
1709 
1710  // Obtain the pending queue and remove it from the cache
1711  Queue<UDPPacketBuffer> queue = null;
1712 
1713  lock (m_pendingCache)
1714  {
1715  if (!m_pendingCache.TryGetValue(endPoint, out queue))
1716  {
1717  m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present");
1718  return;
1719 
1720  }
1721  m_pendingCache.Remove(endPoint);
1722  }
1723 
1724  m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
1725 
1726  // Reinject queued packets
1727  while (queue.Count > 0)
1728  {
1729  UDPPacketBuffer buf = queue.Dequeue();
1730  PacketReceived(buf);
1731  }
1732 
1733  queue = null;
1734 
1735  // Send ack straight away to let the viewer know that the connection is active.
1736  // The client will be null if it already exists (e.g. if on a region crossing the client sends a use
1737  // circuit code to the existing child agent. This is not particularly obvious.
1738  SendAckImmediate(endPoint, uccp.Header.Sequence);
1739 
1740  // We only want to send initial data to new clients, not ones which are being converted from child to root.
1741  if (client != null)
1742  {
1743  bool tp = (aCircuit.teleportFlags > 0);
1744  // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from
1745  if (!tp)
1746  client.SceneAgent.SendInitialDataToMe();
1747  }
1748  }
1749  else
1750  {
1751  // Don't create clients for unauthorized requesters.
1752  m_log.WarnFormat(
1753  "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1754 
1755  uccp.CircuitCode.ID, Scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1756 
1757  lock (m_pendingCache)
1758  m_pendingCache.Remove(endPoint);
1759  }
1760 
1761  // m_log.DebugFormat(
1762  // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms",
1763  // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds);
1764 
1765  }
1766  catch (Exception e)
1767  {
1768  m_log.ErrorFormat(
1769  "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1770  endPoint != null ? endPoint.ToString() : "n/a",
1771  client != null ? client.Name : "unknown",
1772  client != null ? client.AgentId.ToString() : "unknown",
1773  e.Message,
1774  e.StackTrace);
1775  }
1776  }
1777 /*
1778  private void HandleCompleteMovementIntoRegion(object o)
1779  {
1780  IPEndPoint endPoint = null;
1781  IClientAPI client = null;
1782 
1783  try
1784  {
1785  object[] array = (object[])o;
1786  endPoint = (IPEndPoint)array[0];
1787  CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1];
1788 
1789  m_log.DebugFormat(
1790  "[LLUDPSERVER]: Handling CompleteAgentMovement request from {0} in {1}", endPoint, Scene.Name);
1791 
1792  // Determine which agent this packet came from
1793  // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination
1794  // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode
1795  // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these
1796  // packets asynchronously, we need to account for this thread proceeding more quickly than the
1797  // UseCircuitCode thread.
1798  int count = 40;
1799  while (count-- > 0)
1800  {
1801  if (Scene.TryGetClient(endPoint, out client))
1802  {
1803  if (!client.IsActive)
1804  {
1805  // This check exists to catch a condition where the client has been closed by another thread
1806  // but has not yet been removed from the client manager (and possibly a new connection has
1807  // not yet been established).
1808  m_log.DebugFormat(
1809  "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active yet. Waiting.",
1810  endPoint, client.Name, Scene.Name);
1811  }
1812  else if (client.SceneAgent == null)
1813  {
1814  // This check exists to catch a condition where the new client has been added to the client
1815  // manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too
1816  // eager, then the new ScenePresence may not have registered a listener for this messsage
1817  // before we try to process it.
1818  // XXX: A better long term fix may be to add the SceneAgent before the client is added to
1819  // the client manager
1820  m_log.DebugFormat(
1821  "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.",
1822  endPoint, client.Name, Scene.Name);
1823  }
1824  else
1825  {
1826  break;
1827  }
1828  }
1829  else
1830  {
1831  m_log.DebugFormat(
1832  "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.",
1833  endPoint, Scene.Name);
1834  }
1835 
1836  Thread.Sleep(200);
1837  }
1838 
1839  if (client == null)
1840  {
1841  m_log.DebugFormat(
1842  "[LLUDPSERVER]: No client found for CompleteAgentMovement from {0} in {1} after wait. Dropping.",
1843  endPoint, Scene.Name);
1844 
1845  return;
1846  }
1847  else if (!client.IsActive || client.SceneAgent == null)
1848  {
1849  // This check exists to catch a condition where the client has been closed by another thread
1850  // but has not yet been removed from the client manager.
1851  // The packet could be simply ignored but it is useful to know if this condition occurred for other debugging
1852  // purposes.
1853  m_log.DebugFormat(
1854  "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active after wait. Dropping.",
1855  endPoint, client.Name, Scene.Name);
1856 
1857  return;
1858  }
1859 
1860  IncomingPacket incomingPacket1;
1861 
1862  // Inbox insertion
1863  if (UsePools)
1864  {
1865  incomingPacket1 = m_incomingPacketPool.GetObject();
1866  incomingPacket1.Client = (LLClientView)client;
1867  incomingPacket1.Packet = packet;
1868  }
1869  else
1870  {
1871  incomingPacket1 = new IncomingPacket((LLClientView)client, packet);
1872  }
1873 
1874  packetInbox.Enqueue(incomingPacket1);
1875  }
1876  catch (Exception e)
1877  {
1878  m_log.ErrorFormat(
1879  "[LLUDPSERVER]: CompleteAgentMovement handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1880  endPoint != null ? endPoint.ToString() : "n/a",
1881  client != null ? client.Name : "unknown",
1882  client != null ? client.AgentId.ToString() : "unknown",
1883  e.Message,
1884  e.StackTrace);
1885  }
1886  }
1887 */
1888 
1898  private void SendAckImmediate(IPEndPoint remoteEndpoint, uint sequenceNumber)
1899  {
1900  PacketAckPacket ack = new PacketAckPacket();
1901  ack.Header.Reliable = false;
1902  ack.Packets = new PacketAckPacket.PacketsBlock[1];
1903  ack.Packets[0] = new PacketAckPacket.PacketsBlock();
1904  ack.Packets[0].ID = sequenceNumber;
1905 
1906  SendAckImmediate(remoteEndpoint, ack);
1907  }
1908 
1909  public virtual void SendAckImmediate(IPEndPoint remoteEndpoint, PacketAckPacket ack)
1910  {
1911  byte[] packetData = ack.ToBytes();
1912  int length = packetData.Length;
1913 
1914  UDPPacketBuffer buffer = new UDPPacketBuffer(remoteEndpoint, length);
1915  buffer.DataLength = length;
1916 
1917  Buffer.BlockCopy(packetData, 0, buffer.Data, 0, length);
1918 
1919  AsyncBeginSend(buffer);
1920  }
1921 
1922  private bool IsClientAuthorized(UseCircuitCodePacket useCircuitCode, out AuthenticateResponse sessionInfo)
1923  {
1924  UUID agentID = useCircuitCode.CircuitCode.ID;
1925  UUID sessionID = useCircuitCode.CircuitCode.SessionID;
1926  uint circuitCode = useCircuitCode.CircuitCode.Code;
1927 
1928  sessionInfo = m_circuitManager.AuthenticateSession(sessionID, agentID, circuitCode);
1929  return sessionInfo.Authorised;
1930  }
1931 
1941  protected virtual IClientAPI AddClient(
1942  uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
1943  {
1944  IClientAPI client = null;
1945  bool createNew = false;
1946 
1947  // We currently synchronize this code across the whole scene to avoid issues such as
1948  // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done
1949  // consistently, this lock could probably be removed.
1950  lock (this)
1951  {
1952  if (!Scene.TryGetClient(agentID, out client))
1953  {
1954  createNew = true;
1955  }
1956  else
1957  {
1958  if (client.SceneAgent == null)
1959  {
1960  Scene.CloseAgent(agentID, true);
1961  createNew = true;
1962  }
1963  }
1964 
1965  if (createNew)
1966  {
1967  LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, Throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
1968 
1969 
1970  client = new LLClientView(Scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1971  client.OnLogout += LogoutHandler;
1972  client.DebugPacketLevel = DefaultClientPacketDebugLevel;
1973 
1974  ((LLClientView)client).DisableFacelights = m_disableFacelights;
1975 
1976  client.Start();
1977  }
1978  }
1979 
1980  return client;
1981  }
1982 
1992  private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks)
1993  {
1994  lock (client.CloseSyncLock)
1995  {
1996  ClientLogoutsDueToNoReceives++;
1997 
1998  if (client.SceneAgent != null)
1999  {
2000  m_log.WarnFormat(
2001  "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.",
2002  client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, Scene.Name);
2003 
2004  if (!client.SceneAgent.IsChildAgent)
2005  client.Kick("Simulator logged you out due to connection timeout.");
2006  }
2007  }
2008 
2009  if (!Scene.CloseAgent(client.AgentId, true))
2010  client.Close(true,true);
2011  }
2012 
2013  private void IncomingPacketHandler()
2014  {
2015  Thread.CurrentThread.Priority = ThreadPriority.Highest;
2016  IncomingPacket incomingPacket;
2017  // Set this culture for the thread that incoming packets are received
2018  // on to en-US to avoid number parsing issues
2019  Culture.SetCurrentCulture();
2020 
2021  while (IsRunningInbound)
2022  {
2023  Scene.ThreadAlive(1);
2024  try
2025  {
2026  incomingPacket = packetInbox.Dequeue(250);
2027 
2028  if (incomingPacket != null && IsRunningInbound)
2029  {
2030  ProcessInPacket(incomingPacket);
2031 
2032  if (UsePools)
2033  {
2034  incomingPacket.Client = null;
2035  m_incomingPacketPool.ReturnObject(incomingPacket);
2036  }
2037  incomingPacket = null;
2038  }
2039  }
2040  catch(Exception ex)
2041  {
2042  m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex);
2043  }
2044 
2045  Watchdog.UpdateThread();
2046  }
2047 
2048  if (packetInbox.Count() > 0)
2049  m_log.Warn("[LLUDPSERVER]: IncomingPacketHandler is shutting down, dropping " + packetInbox.Count() + " packets");
2050  packetInbox.Clear();
2051 
2052  Watchdog.RemoveThread();
2053  }
2054 
2055  private void OutgoingPacketHandler()
2056  {
2057  Thread.CurrentThread.Priority = ThreadPriority.Highest;
2058 
2059  // Set this culture for the thread that outgoing packets are sent
2060  // on to en-US to avoid number parsing issues
2061  Culture.SetCurrentCulture();
2062 
2063  // Typecast the function to an Action<IClientAPI> once here to avoid allocating a new
2064  // Action generic every round
2065  Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
2066 
2067  while (base.IsRunningOutbound)
2068  {
2069  Scene.ThreadAlive(2);
2070  try
2071  {
2072  m_packetSent = false;
2073 
2074  #region Update Timers
2075 
2076  m_resendUnacked = false;
2077  m_sendAcks = false;
2078  m_sendPing = false;
2079 
2080  // Update elapsed time
2081  int thisTick = Environment.TickCount & Int32.MaxValue;
2082  if (m_tickLastOutgoingPacketHandler > thisTick)
2083  m_elapsedMSOutgoingPacketHandler += ((Int32.MaxValue - m_tickLastOutgoingPacketHandler) + thisTick);
2084  else
2085  m_elapsedMSOutgoingPacketHandler += (thisTick - m_tickLastOutgoingPacketHandler);
2086 
2087  m_tickLastOutgoingPacketHandler = thisTick;
2088 
2089  // Check for pending outgoing resends every 100ms
2090  if (m_elapsedMSOutgoingPacketHandler >= 100)
2091  {
2092  m_resendUnacked = true;
2093  m_elapsedMSOutgoingPacketHandler = 0;
2094  m_elapsed100MSOutgoingPacketHandler += 1;
2095  }
2096 
2097  // Check for pending outgoing ACKs every 500ms
2098  if (m_elapsed100MSOutgoingPacketHandler >= 5)
2099  {
2100  m_sendAcks = true;
2101  m_elapsed100MSOutgoingPacketHandler = 0;
2102  m_elapsed500MSOutgoingPacketHandler += 1;
2103  }
2104 
2105  // Send pings to clients every 5000ms
2106  if (m_elapsed500MSOutgoingPacketHandler >= 10)
2107  {
2108  m_sendPing = true;
2109  m_elapsed500MSOutgoingPacketHandler = 0;
2110  }
2111 
2112  #endregion Update Timers
2113 
2114  // Use this for emergency monitoring -- bug hunting
2115  //if (m_scene.EmergencyMonitoring)
2116  // clientPacketHandler = MonitoredClientOutgoingPacketHandler;
2117  //else
2118  // clientPacketHandler = ClientOutgoingPacketHandler;
2119 
2120  // Handle outgoing packets, resends, acknowledgements, and pings for each
2121  // client. m_packetSent will be set to true if a packet is sent
2122  Scene.ForEachClient(clientPacketHandler);
2123 
2124  m_currentOutgoingClient = null;
2125 
2126  // If nothing was sent, sleep for the minimum amount of time before a
2127  // token bucket could get more tokens
2128 
2129  if (!m_packetSent)
2130  Thread.Sleep((int)TickCountResolution);
2131 
2132  // .... wrong core code removed
2133 
2134 
2135  Watchdog.UpdateThread();
2136  }
2137  catch (Exception ex)
2138  {
2139  m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler loop threw an exception: " + ex.Message, ex);
2140  }
2141  }
2142 
2143  Watchdog.RemoveThread();
2144  }
2145 
2147  {
2148  m_currentOutgoingClient = client;
2149 
2150  try
2151  {
2152  if (client is LLClientView)
2153  {
2154  LLClientView llClient = (LLClientView)client;
2155  LLUDPClient udpClient = llClient.UDPClient;
2156 
2157  if (udpClient.IsConnected)
2158  {
2159  if (m_resendUnacked)
2160  HandleUnacked(llClient);
2161 
2162  if (m_sendAcks)
2163  SendAcks(udpClient);
2164 
2165  if (m_sendPing)
2166  SendPing(udpClient);
2167 
2168  // Dequeue any outgoing packets that are within the throttle limits
2169  if (udpClient.DequeueOutgoing())
2170  m_packetSent = true;
2171  }
2172  }
2173  }
2174  catch (Exception ex)
2175  {
2176  m_log.Error(
2177  string.Format("[LLUDPSERVER]: OutgoingPacketHandler iteration for {0} threw ", client.Name), ex);
2178  }
2179  }
2180 
2181  #region Emergency Monitoring
2182  // Alternative packet handler fuull of instrumentation
2183  // Handy for hunting bugs
2184  private Stopwatch watch1 = new Stopwatch();
2185  private Stopwatch watch2 = new Stopwatch();
2186 
2187  private float avgProcessingTicks = 0;
2188  private float avgResendUnackedTicks = 0;
2189  private float avgSendAcksTicks = 0;
2190  private float avgSendPingTicks = 0;
2191  private float avgDequeueTicks = 0;
2192  private long nticks = 0;
2193  private long nticksUnack = 0;
2194  private long nticksAck = 0;
2195  private long nticksPing = 0;
2196  private int npacksSent = 0;
2197  private int npackNotSent = 0;
2198 
2202  public long IncomingPacketsProcessed { get; private set; }
2203 
2204  private void MonitoredClientOutgoingPacketHandler(IClientAPI client)
2205  {
2206  nticks++;
2207  watch1.Start();
2208  m_currentOutgoingClient = client;
2209 
2210  try
2211  {
2212  if (client is LLClientView)
2213  {
2214  LLClientView llClient = (LLClientView)client;
2215  LLUDPClient udpClient = llClient.UDPClient;
2216 
2217  if (udpClient.IsConnected)
2218  {
2219  if (m_resendUnacked)
2220  {
2221  nticksUnack++;
2222  watch2.Start();
2223 
2224  HandleUnacked(llClient);
2225 
2226  watch2.Stop();
2227  avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack);
2228  watch2.Reset();
2229  }
2230 
2231  if (m_sendAcks)
2232  {
2233  nticksAck++;
2234  watch2.Start();
2235 
2236  SendAcks(udpClient);
2237 
2238  watch2.Stop();
2239  avgSendAcksTicks = (nticksAck - 1) / (float)nticksAck * avgSendAcksTicks + (watch2.ElapsedTicks / (float)nticksAck);
2240  watch2.Reset();
2241  }
2242 
2243  if (m_sendPing)
2244  {
2245  nticksPing++;
2246  watch2.Start();
2247 
2248  SendPing(udpClient);
2249 
2250  watch2.Stop();
2251  avgSendPingTicks = (nticksPing - 1) / (float)nticksPing * avgSendPingTicks + (watch2.ElapsedTicks / (float)nticksPing);
2252  watch2.Reset();
2253  }
2254 
2255  watch2.Start();
2256  // Dequeue any outgoing packets that are within the throttle limits
2257  if (udpClient.DequeueOutgoing())
2258  {
2259  m_packetSent = true;
2260  npacksSent++;
2261  }
2262  else
2263  {
2264  npackNotSent++;
2265  }
2266 
2267  watch2.Stop();
2268  avgDequeueTicks = (nticks - 1) / (float)nticks * avgDequeueTicks + (watch2.ElapsedTicks / (float)nticks);
2269  watch2.Reset();
2270 
2271  }
2272  else
2273  {
2274  m_log.WarnFormat("[LLUDPSERVER]: Client is not connected");
2275  }
2276  }
2277  }
2278  catch (Exception ex)
2279  {
2280  m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name +
2281  " threw an exception: " + ex.Message, ex);
2282  }
2283  watch1.Stop();
2284  avgProcessingTicks = (nticks - 1) / (float)nticks * avgProcessingTicks + (watch1.ElapsedTicks / (float)nticks);
2285  watch1.Reset();
2286 
2287  // reuse this -- it's every ~100ms
2288  if (Scene.EmergencyMonitoring && nticks % 100 == 0)
2289  {
2290  m_log.InfoFormat("[LLUDPSERVER]: avg processing ticks: {0} avg unacked: {1} avg acks: {2} avg ping: {3} avg dequeue: {4} (TickCountRes: {5} sent: {6} notsent: {7})",
2291  avgProcessingTicks, avgResendUnackedTicks, avgSendAcksTicks, avgSendPingTicks, avgDequeueTicks, TickCountResolution, npacksSent, npackNotSent);
2292  npackNotSent = npacksSent = 0;
2293  }
2294 
2295  }
2296 
2297  #endregion
2298 
2299  private void ProcessInPacket(IncomingPacket incomingPacket)
2300  {
2301  Packet packet = incomingPacket.Packet;
2302  LLClientView client = incomingPacket.Client;
2303 
2304  if(!client.IsActive)
2305  return;
2306 
2307  m_currentIncomingClient = client;
2308 
2309  try
2310  {
2311  // Process this packet
2312  client.ProcessInPacket(packet);
2313  }
2314  catch(ThreadAbortException)
2315  {
2316  // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down
2317  m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server");
2318  Stop();
2319  }
2320  catch(Exception e)
2321  {
2322  // Don't let a failure in an individual client thread crash the whole sim.
2323  m_log.Error(
2324  string.Format(
2325  "[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw ",
2326  client.Name,packet.Type),
2327  e);
2328  }
2329  finally
2330  {
2331  m_currentIncomingClient = null;
2332  }
2333 
2334  IncomingPacketsProcessed++;
2335  }
2336 
2337  protected void LogoutHandler(IClientAPI client)
2338  {
2339  client.SendLogoutPacket();
2340 
2341  if (!client.IsLoggingOut)
2342  {
2343  client.IsLoggingOut = true;
2344  Scene.CloseAgent(client.AgentId, false);
2345  }
2346  }
2347  }
2348 }
virtual IClientAPI AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
Add a client.
virtual void SendAckImmediate(IPEndPoint remoteEndpoint, PacketAckPacket ack)
static void LogPacketHeader(bool incoming, uint circuit, byte flags, PacketType packetType, ushort size)
bool IsActive
As well as it's function in IClientAPI, in LLClientView we are locking on this property in order to p...
const int MTU
Maximum transmission unit, or UDP packet size, for the LLUDP protocol
Definition: LLUDPServer.cs:257
Packet Packet
Packet data that has been received
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
Definition: LLUDPServer.cs:80
OpenSim.Region.ClientStack.LindenUDP.TokenBucket TokenBucket
Definition: LLUDPServer.cs:46
A hierarchical token bucket for bandwidth throttling. See http://en.wikipedia.org/wiki/Token_bucket f...
Definition: TokenBucket.cs:42
void ResendUnacked(OutgoingPacket outgoingPacket)
int TickLastPacketReceived
Environment.TickCount when the last packet was received for this client
Definition: LLUDPClient.cs:140
Handles new client connections Constructor takes a single Packet and authenticates everything ...
Definition: LLClientView.cs:65
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
Definition: LLUDPServer.cs:91
bool SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method)
Start the process of sending a packet to the client.
Definition: LLUDPServer.cs:949
Holds individual statistic details
Definition: Stat.cs:41
bool IsChildAgent
If true, then the agent has no avatar in the scene. The agent exists to relay data from a region that...
Definition: ISceneAgent.cs:56
long BlocksRequested
Number of packet blocks requested.
Definition: PacketPool.cs:97
void Acknowledge(uint sequenceNumber, int currentTime, bool fromResend)
Marks a packet as acknowledged This method is used when an acknowledgement is received from the netwo...
readonly IPEndPoint RemoteEndPoint
The remote address of the connected client
Definition: LLUDPClient.cs:119
readonly IncomingPacketHistoryCollection PacketArchive
Sequence numbers of packets we've received (for duplicate checking)
Definition: LLUDPClient.cs:123
void Close()
Close down the client view
long BlocksReused
Number of packet blocks reused.
Definition: PacketPool.cs:102
bool IsPaused
True when this connection is paused, otherwise false
Definition: LLUDPClient.cs:138
bool IsConnected
True when this connection is alive, otherwise false
Definition: LLUDPClient.cs:136
OpenSim.Region.ClientStack.LindenUDP.TokenBucket TokenBucket
Definition: LLUDPClient.cs:38
virtual void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting, UnackedPacketMethod method)
Start the process of sending a packet to the client.
Definition: LLUDPServer.cs:899
Tracks state for a client UDP connection and provides client-specific methods
Definition: LLUDPClient.cs:66
A shim around LLUDPServer that implements the IClientNetworkServer interface
Definition: LLUDPServer.cs:54
UnackedPacketMethod UnackedMethod
The delegate to be called if this packet is determined to be unacknowledged
readonly UnackedPacketCollection NeedAcks
Packets we have sent that need to be ACKed by the client
Definition: LLUDPClient.cs:126
bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue)
Queue an outgoing packet if appropriate.
Definition: LLUDPClient.cs:563
byte CurrentPingSequence
Current ping sequence number
Definition: LLUDPClient.cs:134
Circuit data for an agent. Connection information shared between regions that accept UDP connections ...
string Name
The name of this scene.
Definition: IScene.cs:62
Holds a reference to a LLUDPClient, Packetand a for incoming packets
Holds drip rates and maximum burst rates for throttling with hierarchical token buckets. The maximum burst rates set here are hard limits and can not be overridden by client requests
static ICommandConsole Instance
Definition: MainConsole.cs:35
readonly DoubleLocklessQueue< uint > PendingAcks
ACKs that are queued up, waiting to be sent to the client
Definition: LLUDPClient.cs:129
bool DequeueOutgoing()
Loops through all of the packet queues for this client and tries to send an outgoing packet from each...
Definition: LLUDPClient.cs:628
StatVerbosity
Verbosity of stat.
UDPPacketBuffer Buffer
Packet data to send
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
Definition: LLUDPServer.cs:76
bool m_sendAcks
Flag to signal when clients should send ACKs
Definition: LLUDPServer.cs:342
override void StartOutbound()
Start outbound UDP packet handling.
Definition: LLUDPServer.cs:559
The LLUDP server for a region. This handles incoming and outgoing packets for all UDP connections to ...
Definition: LLUDPServer.cs:252
bool IsLoggingOut
Set if the client is closing due to a logout request
Definition: IClientAPI.cs:773
readonly int PrimUpdatesPerCallback
Number of prim updates to put on the queue each time the OnQueueEmpty event is triggered for updates...
Definition: LLUDPServer.cs:278
LLUDPClient Client
Client this packet is destined for
void Initialise(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager)
Definition: LLUDPServer.cs:102
Object CloseSyncLock
Used to synchronise threads when client is being closed.
void CompletePing(LLUDPClient udpClient, byte pingID)
LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager)
Definition: LLUDPServer.cs:445
int DebugDataOutLevel
Controls whether information is logged about each outbound packet immediately before it is sent...
Definition: LLUDPClient.cs:83
List< ScenePresence > GetScenePresences()
Gets all the scene presences in this scene.
Definition: Scene.cs:5259
readonly int TextureSendLimit
Number of texture packets to put on the queue each time the OnQueueEmpty event is triggered for textu...
Definition: LLUDPServer.cs:282
bool m_sendPing
Flag to signal when clients should send pings
Definition: LLUDPServer.cs:345
readonly float TickCountResolution
The measured resolution of Environment.TickCount
Definition: LLUDPServer.cs:274
Packet GetPacket(PacketType type)
Gets a packet of the given type.
Definition: PacketPool.cs:116
long PacketsRequested
Number of packets requested.
Definition: PacketPool.cs:87
readonly uint CircuitCode
Circuit code that this client is connected on
Definition: LLUDPClient.cs:121
bool TryGetClient(UUID avatarID, out IClientAPI client)
Definition: Scene.cs:5432
AgentCircuitManager AuthenticateHandler
Definition: Scene.cs:805
MeasuresOfInterest
Measures of interest for this stat.
long PacketsReused
Number of packets reused.
Definition: PacketPool.cs:92
bool m_resendUnacked
Flag to signal when clients should check for resends
Definition: LLUDPServer.cs:339
bool CloseAgent(UUID agentID, bool force, string auth_token)
Authenticated close (via network)
Definition: Scene.cs:4757
delegate void UnackedPacketMethod(OutgoingPacket oPacket)
void Initialise(IConfigSource source)
This is called to initialize the region module. For shared modules, this is called exactly once...
Definition: LLUDPServer.cs:71
int CurrentSequence
Current packet sequence number
Definition: LLUDPClient.cs:132
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
Definition: LLUDPServer.cs:96
Holds a reference to the LLUDPClientthis packet is destined for, along with the serialized packet dat...
override void PacketReceived(UDPPacketBuffer buffer)
This method is called when an incoming packet is received