LLUDPServer.cs 73 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833
  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. using System;
  28. using System.Collections.Generic;
  29. using System.Diagnostics;
  30. using System.IO;
  31. using System.Net;
  32. using System.Net.Sockets;
  33. using System.Reflection;
  34. using System.Threading;
  35. using log4net;
  36. using Nini.Config;
  37. using OpenMetaverse.Packets;
  38. using OpenSim.Framework;
  39. using OpenSim.Framework.Console;
  40. using OpenSim.Framework.Monitoring;
  41. using OpenSim.Region.Framework.Scenes;
  42. using OpenMetaverse;
  43. using TokenBucket = OpenSim.Region.ClientStack.LindenUDP.TokenBucket;
  44. namespace OpenSim.Region.ClientStack.LindenUDP
  45. {
  46. /// <summary>
  47. /// A shim around LLUDPServer that implements the IClientNetworkServer interface
  48. /// </summary>
  49. public sealed class LLUDPServerShim : IClientNetworkServer
  50. {
  51. LLUDPServer m_udpServer;
  52. public LLUDPServerShim()
  53. {
  54. }
  55. public void Initialise(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager)
  56. {
  57. m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager);
  58. }
  59. public void NetworkStop()
  60. {
  61. m_udpServer.Stop();
  62. }
  63. public void AddScene(IScene scene)
  64. {
  65. m_udpServer.AddScene(scene);
  66. StatsManager.RegisterStat(
  67. new Stat(
  68. "IncomingPacketsProcessedCount",
  69. "Number of inbound UDP packets processed",
  70. "Number of inbound UDP packets processed",
  71. "",
  72. "clientstack",
  73. scene.Name,
  74. StatType.Pull,
  75. MeasuresOfInterest.AverageChangeOverTime,
  76. stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
  77. StatVerbosity.Debug));
  78. }
  79. public bool HandlesRegion(Location x)
  80. {
  81. return m_udpServer.HandlesRegion(x);
  82. }
  83. public void Start()
  84. {
  85. m_udpServer.Start();
  86. }
  87. public void Stop()
  88. {
  89. m_udpServer.Stop();
  90. }
  91. }
  92. /// <summary>
  93. /// The LLUDP server for a region. This handles incoming and outgoing
  94. /// packets for all UDP connections to the region
  95. /// </summary>
  96. public class LLUDPServer : OpenSimUDPBase
  97. {
  98. /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary>
  99. public const int MTU = 1400;
  100. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  101. /// <summary>The measured resolution of Environment.TickCount</summary>
  102. public readonly float TickCountResolution;
  103. /// <summary>Number of prim updates to put on the queue each time the
  104. /// OnQueueEmpty event is triggered for updates</summary>
  105. public readonly int PrimUpdatesPerCallback;
  106. /// <summary>Number of texture packets to put on the queue each time the
  107. /// OnQueueEmpty event is triggered for textures</summary>
  108. public readonly int TextureSendLimit;
  109. /// <summary>Handlers for incoming packets</summary>
  110. //PacketEventDictionary packetEvents = new PacketEventDictionary();
  111. /// <summary>Incoming packets that are awaiting handling</summary>
  112. private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
  113. /// <summary></summary>
  114. //private UDPClientCollection m_clients = new UDPClientCollection();
  115. /// <summary>Bandwidth throttle for this UDP server</summary>
  116. protected TokenBucket m_throttle;
  117. /// <summary>Bandwidth throttle rates for this UDP server</summary>
  118. public ThrottleRates ThrottleRates { get; private set; }
  119. /// <summary>Manages authentication for agent circuits</summary>
  120. private AgentCircuitManager m_circuitManager;
  121. /// <summary>Reference to the scene this UDP server is attached to</summary>
  122. protected Scene m_scene;
  123. /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary>
  124. private Location m_location;
  125. /// <summary>The size of the receive buffer for the UDP socket. This value
  126. /// is passed up to the operating system and used in the system networking
  127. /// stack. Use zero to leave this value as the default</summary>
  128. private int m_recvBufferSize;
  129. /// <summary>Flag to process packets asynchronously or synchronously</summary>
  130. private bool m_asyncPacketHandling;
  131. /// <summary>Tracks whether or not a packet was sent each round so we know
  132. /// whether or not to sleep</summary>
  133. private bool m_packetSent;
  134. /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary>
  135. private int m_elapsedMSSinceLastStatReport = 0;
  136. /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary>
  137. private int m_tickLastOutgoingPacketHandler;
  138. /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary>
  139. private int m_elapsedMSOutgoingPacketHandler;
  140. /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary>
  141. private int m_elapsed100MSOutgoingPacketHandler;
  142. /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary>
  143. private int m_elapsed500MSOutgoingPacketHandler;
  144. /// <summary>Flag to signal when clients should check for resends</summary>
  145. protected bool m_resendUnacked;
  146. /// <summary>Flag to signal when clients should send ACKs</summary>
  147. protected bool m_sendAcks;
  148. /// <summary>Flag to signal when clients should send pings</summary>
  149. protected bool m_sendPing;
  150. private Pool<IncomingPacket> m_incomingPacketPool;
  151. /// <summary>
  152. /// Stat for number of packets in the main pool awaiting use.
  153. /// </summary>
  154. private Stat m_poolCountStat;
  155. /// <summary>
  156. /// Stat for number of packets in the inbound packet pool awaiting use.
  157. /// </summary>
  158. private Stat m_incomingPacketPoolStat;
  159. private int m_defaultRTO = 0;
  160. private int m_maxRTO = 0;
  161. private int m_ackTimeout = 0;
  162. private int m_pausedAckTimeout = 0;
  163. private bool m_disableFacelights = false;
  164. public Socket Server { get { return null; } }
  165. private int m_malformedCount = 0; // Guard against a spamming attack
  166. /// <summary>
  167. /// Record current outgoing client for monitoring purposes.
  168. /// </summary>
  169. private IClientAPI m_currentOutgoingClient;
  170. /// <summary>
  171. /// Recording current incoming client for monitoring purposes.
  172. /// </summary>
  173. private IClientAPI m_currentIncomingClient;
  174. public LLUDPServer(
  175. IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port,
  176. IConfigSource configSource, AgentCircuitManager circuitManager)
  177. : base(listenIP, (int)port)
  178. {
  179. #region Environment.TickCount Measurement
  180. // Measure the resolution of Environment.TickCount
  181. TickCountResolution = 0f;
  182. for (int i = 0; i < 5; i++)
  183. {
  184. int start = Environment.TickCount;
  185. int now = start;
  186. while (now == start)
  187. now = Environment.TickCount;
  188. TickCountResolution += (float)(now - start) * 0.2f;
  189. }
  190. m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms");
  191. TickCountResolution = (float)Math.Ceiling(TickCountResolution);
  192. #endregion Environment.TickCount Measurement
  193. m_circuitManager = circuitManager;
  194. int sceneThrottleBps = 0;
  195. bool usePools = false;
  196. IConfig config = configSource.Configs["ClientStack.LindenUDP"];
  197. if (config != null)
  198. {
  199. m_asyncPacketHandling = config.GetBoolean("async_packet_handling", true);
  200. m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0);
  201. sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0);
  202. PrimUpdatesPerCallback = config.GetInt("PrimUpdatesPerCallback", 100);
  203. TextureSendLimit = config.GetInt("TextureSendLimit", 20);
  204. m_defaultRTO = config.GetInt("DefaultRTO", 0);
  205. m_maxRTO = config.GetInt("MaxRTO", 0);
  206. m_disableFacelights = config.GetBoolean("DisableFacelights", false);
  207. m_ackTimeout = 1000 * config.GetInt("AckTimeout", 60);
  208. m_pausedAckTimeout = 1000 * config.GetInt("PausedAckTimeout", 300);
  209. }
  210. else
  211. {
  212. PrimUpdatesPerCallback = 100;
  213. TextureSendLimit = 20;
  214. m_ackTimeout = 1000 * 60; // 1 minute
  215. m_pausedAckTimeout = 1000 * 300; // 5 minutes
  216. }
  217. // FIXME: This actually only needs to be done once since the PacketPool is shared across all servers.
  218. // However, there is no harm in temporarily doing it multiple times.
  219. IConfig packetConfig = configSource.Configs["PacketPool"];
  220. if (packetConfig != null)
  221. {
  222. PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true);
  223. PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true);
  224. usePools = packetConfig.GetBoolean("RecycleBaseUDPPackets", usePools);
  225. }
  226. #region BinaryStats
  227. config = configSource.Configs["Statistics.Binary"];
  228. m_shouldCollectStats = false;
  229. if (config != null)
  230. {
  231. if (config.Contains("enabled") && config.GetBoolean("enabled"))
  232. {
  233. if (config.Contains("collect_packet_headers"))
  234. m_shouldCollectStats = config.GetBoolean("collect_packet_headers");
  235. if (config.Contains("packet_headers_period_seconds"))
  236. {
  237. binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt("region_stats_period_seconds"));
  238. }
  239. if (config.Contains("stats_dir"))
  240. {
  241. binStatsDir = config.GetString("stats_dir");
  242. }
  243. }
  244. else
  245. {
  246. m_shouldCollectStats = false;
  247. }
  248. }
  249. #endregion BinaryStats
  250. m_throttle = new TokenBucket(null, sceneThrottleBps);
  251. ThrottleRates = new ThrottleRates(configSource);
  252. if (usePools)
  253. EnablePools();
  254. }
  255. public void Start()
  256. {
  257. StartInbound();
  258. StartOutbound();
  259. m_elapsedMSSinceLastStatReport = Environment.TickCount;
  260. }
  261. private void StartInbound()
  262. {
  263. m_log.InfoFormat(
  264. "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}",
  265. m_asyncPacketHandling ? "asynchronous" : "synchronous", UsePools);
  266. base.StartInbound(m_recvBufferSize, m_asyncPacketHandling);
  267. // This thread will process the packets received that are placed on the packetInbox
  268. Watchdog.StartThread(
  269. IncomingPacketHandler,
  270. string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName),
  271. ThreadPriority.Normal,
  272. false,
  273. true,
  274. GetWatchdogIncomingAlarmData,
  275. Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
  276. }
  277. private new void StartOutbound()
  278. {
  279. m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server");
  280. base.StartOutbound();
  281. Watchdog.StartThread(
  282. OutgoingPacketHandler,
  283. string.Format("Outgoing Packets ({0})", m_scene.RegionInfo.RegionName),
  284. ThreadPriority.Normal,
  285. false,
  286. true,
  287. GetWatchdogOutgoingAlarmData,
  288. Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
  289. }
  290. public void Stop()
  291. {
  292. m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
  293. base.StopOutbound();
  294. base.StopInbound();
  295. }
  296. protected override bool EnablePools()
  297. {
  298. if (!UsePools)
  299. {
  300. base.EnablePools();
  301. m_incomingPacketPool = new Pool<IncomingPacket>(() => new IncomingPacket(), 500);
  302. return true;
  303. }
  304. return false;
  305. }
  306. protected override bool DisablePools()
  307. {
  308. if (UsePools)
  309. {
  310. base.DisablePools();
  311. StatsManager.DeregisterStat(m_incomingPacketPoolStat);
  312. // We won't null out the pool to avoid a race condition with code that may be in the middle of using it.
  313. return true;
  314. }
  315. return false;
  316. }
  317. /// <summary>
  318. /// This is a seperate method so that it can be called once we have an m_scene to distinguish different scene
  319. /// stats.
  320. /// </summary>
  321. private void EnablePoolStats()
  322. {
  323. m_poolCountStat
  324. = new Stat(
  325. "UDPPacketBufferPoolCount",
  326. "Objects within the UDPPacketBuffer pool",
  327. "The number of objects currently stored within the UDPPacketBuffer pool",
  328. "",
  329. "clientstack",
  330. m_scene.Name,
  331. StatType.Pull,
  332. stat => stat.Value = Pool.Count,
  333. StatVerbosity.Debug);
  334. StatsManager.RegisterStat(m_poolCountStat);
  335. m_incomingPacketPoolStat
  336. = new Stat(
  337. "IncomingPacketPoolCount",
  338. "Objects within incoming packet pool",
  339. "The number of objects currently stored within the incoming packet pool",
  340. "",
  341. "clientstack",
  342. m_scene.Name,
  343. StatType.Pull,
  344. stat => stat.Value = m_incomingPacketPool.Count,
  345. StatVerbosity.Debug);
  346. StatsManager.RegisterStat(m_incomingPacketPoolStat);
  347. }
  348. /// <summary>
  349. /// Disables pool stats.
  350. /// </summary>
  351. private void DisablePoolStats()
  352. {
  353. StatsManager.DeregisterStat(m_poolCountStat);
  354. m_poolCountStat = null;
  355. StatsManager.DeregisterStat(m_incomingPacketPoolStat);
  356. m_incomingPacketPoolStat = null;
  357. }
  358. /// <summary>
  359. /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging.
  360. /// </summary>
  361. /// <returns></returns>
  362. private string GetWatchdogIncomingAlarmData()
  363. {
  364. return string.Format(
  365. "Client is {0}",
  366. m_currentIncomingClient != null ? m_currentIncomingClient.Name : "none");
  367. }
  368. /// <summary>
  369. /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging.
  370. /// </summary>
  371. /// <returns></returns>
  372. private string GetWatchdogOutgoingAlarmData()
  373. {
  374. return string.Format(
  375. "Client is {0}",
  376. m_currentOutgoingClient != null ? m_currentOutgoingClient.Name : "none");
  377. }
  378. public void AddScene(IScene scene)
  379. {
  380. if (m_scene != null)
  381. {
  382. m_log.Error("[LLUDPSERVER]: AddScene() called on an LLUDPServer that already has a scene");
  383. return;
  384. }
  385. if (!(scene is Scene))
  386. {
  387. m_log.Error("[LLUDPSERVER]: AddScene() called with an unrecognized scene type " + scene.GetType());
  388. return;
  389. }
  390. m_scene = (Scene)scene;
  391. m_location = new Location(m_scene.RegionInfo.RegionHandle);
  392. // XXX: These stats are also pool stats but we register them separately since they are currently not
  393. // turned on and off by EnablePools()/DisablePools()
  394. StatsManager.RegisterStat(
  395. new PercentageStat(
  396. "PacketsReused",
  397. "Packets reused",
  398. "Number of packets reused out of all requests to the packet pool",
  399. "clientstack",
  400. m_scene.Name,
  401. StatType.Pull,
  402. stat =>
  403. { PercentageStat pstat = (PercentageStat)stat;
  404. pstat.Consequent = PacketPool.Instance.PacketsRequested;
  405. pstat.Antecedent = PacketPool.Instance.PacketsReused; },
  406. StatVerbosity.Debug));
  407. StatsManager.RegisterStat(
  408. new PercentageStat(
  409. "PacketDataBlocksReused",
  410. "Packet data blocks reused",
  411. "Number of data blocks reused out of all requests to the packet pool",
  412. "clientstack",
  413. m_scene.Name,
  414. StatType.Pull,
  415. stat =>
  416. { PercentageStat pstat = (PercentageStat)stat;
  417. pstat.Consequent = PacketPool.Instance.BlocksRequested;
  418. pstat.Antecedent = PacketPool.Instance.BlocksReused; },
  419. StatVerbosity.Debug));
  420. StatsManager.RegisterStat(
  421. new Stat(
  422. "PacketsPoolCount",
  423. "Objects within the packet pool",
  424. "The number of objects currently stored within the packet pool",
  425. "",
  426. "clientstack",
  427. m_scene.Name,
  428. StatType.Pull,
  429. stat => stat.Value = PacketPool.Instance.PacketsPooled,
  430. StatVerbosity.Debug));
  431. StatsManager.RegisterStat(
  432. new Stat(
  433. "PacketDataBlocksPoolCount",
  434. "Objects within the packet data block pool",
  435. "The number of objects currently stored within the packet data block pool",
  436. "",
  437. "clientstack",
  438. m_scene.Name,
  439. StatType.Pull,
  440. stat => stat.Value = PacketPool.Instance.BlocksPooled,
  441. StatVerbosity.Debug));
  442. // We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by
  443. // scene name
  444. if (UsePools)
  445. EnablePoolStats();
  446. MainConsole.Instance.Commands.AddCommand(
  447. "Debug",
  448. false,
  449. "debug lludp start",
  450. "debug lludp start <in|out|all>",
  451. "Control LLUDP packet processing.",
  452. "No effect if packet processing has already started.\n"
  453. + "in - start inbound processing.\n"
  454. + "out - start outbound processing.\n"
  455. + "all - start in and outbound processing.\n",
  456. HandleStartCommand);
  457. MainConsole.Instance.Commands.AddCommand(
  458. "Debug",
  459. false,
  460. "debug lludp stop",
  461. "debug lludp stop <in|out|all>",
  462. "Stop LLUDP packet processing.",
  463. "No effect if packet processing has already stopped.\n"
  464. + "in - stop inbound processing.\n"
  465. + "out - stop outbound processing.\n"
  466. + "all - stop in and outbound processing.\n",
  467. HandleStopCommand);
  468. MainConsole.Instance.Commands.AddCommand(
  469. "Debug",
  470. false,
  471. "debug lludp pool",
  472. "debug lludp pool <on|off>",
  473. "Turn object pooling within the lludp component on or off.",
  474. HandlePoolCommand);
  475. MainConsole.Instance.Commands.AddCommand(
  476. "Debug",
  477. false,
  478. "debug lludp status",
  479. "debug lludp status",
  480. "Return status of LLUDP packet processing.",
  481. HandleStatusCommand);
  482. }
  483. private void HandleStartCommand(string module, string[] args)
  484. {
  485. if (args.Length != 4)
  486. {
  487. MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
  488. return;
  489. }
  490. string subCommand = args[3];
  491. if (subCommand == "in" || subCommand == "all")
  492. StartInbound();
  493. if (subCommand == "out" || subCommand == "all")
  494. StartOutbound();
  495. }
  496. private void HandleStopCommand(string module, string[] args)
  497. {
  498. if (args.Length != 4)
  499. {
  500. MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
  501. return;
  502. }
  503. string subCommand = args[3];
  504. if (subCommand == "in" || subCommand == "all")
  505. StopInbound();
  506. if (subCommand == "out" || subCommand == "all")
  507. StopOutbound();
  508. }
  509. private void HandlePoolCommand(string module, string[] args)
  510. {
  511. if (args.Length != 4)
  512. {
  513. MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
  514. return;
  515. }
  516. string enabled = args[3];
  517. if (enabled == "on")
  518. {
  519. if (EnablePools())
  520. {
  521. EnablePoolStats();
  522. MainConsole.Instance.OutputFormat("Packet pools enabled on {0}", m_scene.Name);
  523. }
  524. }
  525. else if (enabled == "off")
  526. {
  527. if (DisablePools())
  528. {
  529. DisablePoolStats();
  530. MainConsole.Instance.OutputFormat("Packet pools disabled on {0}", m_scene.Name);
  531. }
  532. }
  533. else
  534. {
  535. MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
  536. }
  537. }
  538. private void HandleStatusCommand(string module, string[] args)
  539. {
  540. MainConsole.Instance.OutputFormat(
  541. "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled");
  542. MainConsole.Instance.OutputFormat(
  543. "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled");
  544. MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off");
  545. }
  546. public bool HandlesRegion(Location x)
  547. {
  548. return x == m_location;
  549. }
  550. public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting)
  551. {
  552. // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way
  553. if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting)
  554. allowSplitting = false;
  555. if (allowSplitting && packet.HasVariableBlocks)
  556. {
  557. byte[][] datas = packet.ToBytesMultiple();
  558. int packetCount = datas.Length;
  559. if (packetCount < 1)
  560. m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length);
  561. for (int i = 0; i < packetCount; i++)
  562. {
  563. byte[] data = datas[i];
  564. m_scene.ForEachClient(
  565. delegate(IClientAPI client)
  566. {
  567. if (client is LLClientView)
  568. SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
  569. }
  570. );
  571. }
  572. }
  573. else
  574. {
  575. byte[] data = packet.ToBytes();
  576. m_scene.ForEachClient(
  577. delegate(IClientAPI client)
  578. {
  579. if (client is LLClientView)
  580. SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
  581. }
  582. );
  583. }
  584. }
  585. /// <summary>
  586. /// Start the process of sending a packet to the client.
  587. /// </summary>
  588. /// <param name="udpClient"></param>
  589. /// <param name="packet"></param>
  590. /// <param name="category"></param>
  591. /// <param name="allowSplitting"></param>
  592. /// <param name="method">
  593. /// The method to call if the packet is not acked by the client. If null, then a standard
  594. /// resend of the packet is done.
  595. /// </param>
  596. public virtual void SendPacket(
  597. LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting, UnackedPacketMethod method)
  598. {
  599. // CoarseLocationUpdate packets cannot be split in an automated way
  600. if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
  601. allowSplitting = false;
  602. if (allowSplitting && packet.HasVariableBlocks)
  603. {
  604. byte[][] datas = packet.ToBytesMultiple();
  605. int packetCount = datas.Length;
  606. if (packetCount < 1)
  607. m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length);
  608. for (int i = 0; i < packetCount; i++)
  609. {
  610. byte[] data = datas[i];
  611. SendPacketData(udpClient, data, packet.Type, category, method);
  612. }
  613. }
  614. else
  615. {
  616. byte[] data = packet.ToBytes();
  617. SendPacketData(udpClient, data, packet.Type, category, method);
  618. }
  619. PacketPool.Instance.ReturnPacket(packet);
  620. }
  621. /// <summary>
  622. /// Start the process of sending a packet to the client.
  623. /// </summary>
  624. /// <param name="udpClient"></param>
  625. /// <param name="data"></param>
  626. /// <param name="type"></param>
  627. /// <param name="category"></param>
  628. /// <param name="method">
  629. /// The method to call if the packet is not acked by the client. If null, then a standard
  630. /// resend of the packet is done.
  631. /// </param>
  632. public void SendPacketData(
  633. LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method)
  634. {
  635. int dataLength = data.Length;
  636. bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0;
  637. bool doCopy = true;
  638. // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum.
  639. // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting
  640. // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here
  641. // to accomodate for both common scenarios and provide ample room for ACK appending in both
  642. int bufferSize = (dataLength > 180) ? LLUDPServer.MTU : 200;
  643. UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize);
  644. // Zerocode if needed
  645. if (doZerocode)
  646. {
  647. try
  648. {
  649. dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data);
  650. doCopy = false;
  651. }
  652. catch (IndexOutOfRangeException)
  653. {
  654. // The packet grew larger than the bufferSize while zerocoding.
  655. // Remove the MSG_ZEROCODED flag and send the unencoded data
  656. // instead
  657. m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". DataLength=" + dataLength +
  658. " and BufferLength=" + buffer.Data.Length + ". Removing MSG_ZEROCODED flag");
  659. data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED);
  660. }
  661. }
  662. // If the packet data wasn't already copied during zerocoding, copy it now
  663. if (doCopy)
  664. {
  665. if (dataLength <= buffer.Data.Length)
  666. {
  667. Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
  668. }
  669. else
  670. {
  671. bufferSize = dataLength;
  672. buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize);
  673. // m_log.Error("[LLUDPSERVER]: Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" +
  674. // type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length + ". Dropping packet");
  675. Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
  676. }
  677. }
  678. buffer.DataLength = dataLength;
  679. #region Queue or Send
  680. OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null);
  681. // If we were not provided a method for handling unacked, use the UDPServer default method
  682. outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method);
  683. // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will
  684. // continue to display the deleted object until relog. Therefore, we need to always queue a kill object
  685. // packet so that it isn't sent before a queued update packet.
  686. bool requestQueue = type == PacketType.KillObject;
  687. if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue))
  688. SendPacketFinal(outgoingPacket);
  689. #endregion Queue or Send
  690. }
  691. public void SendAcks(LLUDPClient udpClient)
  692. {
  693. uint ack;
  694. if (udpClient.PendingAcks.Dequeue(out ack))
  695. {
  696. List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>();
  697. PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock();
  698. block.ID = ack;
  699. blocks.Add(block);
  700. while (udpClient.PendingAcks.Dequeue(out ack))
  701. {
  702. block = new PacketAckPacket.PacketsBlock();
  703. block.ID = ack;
  704. blocks.Add(block);
  705. }
  706. PacketAckPacket packet = new PacketAckPacket();
  707. packet.Header.Reliable = false;
  708. packet.Packets = blocks.ToArray();
  709. SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true, null);
  710. }
  711. }
  712. public void SendPing(LLUDPClient udpClient)
  713. {
  714. StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck);
  715. pc.Header.Reliable = false;
  716. pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++;
  717. // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit
  718. pc.PingID.OldestUnacked = 0;
  719. SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null);
  720. }
  721. public void CompletePing(LLUDPClient udpClient, byte pingID)
  722. {
  723. CompletePingCheckPacket completePing = new CompletePingCheckPacket();
  724. completePing.PingID.PingID = pingID;
  725. SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false, null);
  726. }
  727. public void HandleUnacked(LLClientView client)
  728. {
  729. LLUDPClient udpClient = client.UDPClient;
  730. if (!udpClient.IsConnected)
  731. return;
  732. // Disconnect an agent if no packets are received for some time
  733. int timeoutTicks = m_ackTimeout;
  734. // Allow more slack if the client is "paused" eg file upload dialogue is open
  735. // Some sort of limit is needed in case the client crashes, loses its network connection
  736. // or some other disaster prevents it from sendung the AgentResume
  737. if (udpClient.IsPaused)
  738. timeoutTicks = m_pausedAckTimeout;
  739. if (client.IsActive &&
  740. (Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > timeoutTicks)
  741. {
  742. // We must set IsActive synchronously so that we can stop the packet loop reinvoking this method, even
  743. // though it's set later on by LLClientView.Close()
  744. client.IsActive = false;
  745. // Fire this out on a different thread so that we don't hold up outgoing packet processing for
  746. // everybody else if this is being called due to an ack timeout.
  747. // This is the same as processing as the async process of a logout request.
  748. Util.FireAndForget(o => DeactivateClientDueToTimeout(client));
  749. return;
  750. }
  751. // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO
  752. List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO);
  753. if (expiredPackets != null)
  754. {
  755. //m_log.Debug("[LLUDPSERVER]: Handling " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO);
  756. // Exponential backoff of the retransmission timeout
  757. udpClient.BackoffRTO();
  758. for (int i = 0; i < expiredPackets.Count; ++i)
  759. expiredPackets[i].UnackedMethod(expiredPackets[i]);
  760. }
  761. }
  762. public void ResendUnacked(OutgoingPacket outgoingPacket)
  763. {
  764. //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
  765. // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
  766. // Set the resent flag
  767. outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
  768. outgoingPacket.Category = ThrottleOutPacketType.Resend;
  769. // Bump up the resend count on this packet
  770. Interlocked.Increment(ref outgoingPacket.ResendCount);
  771. // Requeue or resend the packet
  772. if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, false))
  773. SendPacketFinal(outgoingPacket);
  774. }
  775. public void Flush(LLUDPClient udpClient)
  776. {
  777. // FIXME: Implement?
  778. }
  779. /// <summary>
  780. /// Actually send a packet to a client.
  781. /// </summary>
  782. /// <param name="outgoingPacket"></param>
  783. internal void SendPacketFinal(OutgoingPacket outgoingPacket)
  784. {
  785. UDPPacketBuffer buffer = outgoingPacket.Buffer;
  786. byte flags = buffer.Data[0];
  787. bool isResend = (flags & Helpers.MSG_RESENT) != 0;
  788. bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0;
  789. bool isZerocoded = (flags & Helpers.MSG_ZEROCODED) != 0;
  790. LLUDPClient udpClient = outgoingPacket.Client;
  791. if (!udpClient.IsConnected)
  792. return;
  793. #region ACK Appending
  794. int dataLength = buffer.DataLength;
  795. // NOTE: I'm seeing problems with some viewers when ACKs are appended to zerocoded packets so I've disabled that here
  796. if (!isZerocoded)
  797. {
  798. // Keep appending ACKs until there is no room left in the buffer or there are
  799. // no more ACKs to append
  800. uint ackCount = 0;
  801. uint ack;
  802. while (dataLength + 5 < buffer.Data.Length && udpClient.PendingAcks.Dequeue(out ack))
  803. {
  804. Utils.UIntToBytesBig(ack, buffer.Data, dataLength);
  805. dataLength += 4;
  806. ++ackCount;
  807. }
  808. if (ackCount > 0)
  809. {
  810. // Set the last byte of the packet equal to the number of appended ACKs
  811. buffer.Data[dataLength++] = (byte)ackCount;
  812. // Set the appended ACKs flag on this packet
  813. buffer.Data[0] = (byte)(buffer.Data[0] | Helpers.MSG_APPENDED_ACKS);
  814. }
  815. }
  816. buffer.DataLength = dataLength;
  817. #endregion ACK Appending
  818. #region Sequence Number Assignment
  819. if (!isResend)
  820. {
  821. // Not a resend, assign a new sequence number
  822. uint sequenceNumber = (uint)Interlocked.Increment(ref udpClient.CurrentSequence);
  823. Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1);
  824. outgoingPacket.SequenceNumber = sequenceNumber;
  825. if (isReliable)
  826. {
  827. // Add this packet to the list of ACK responses we are waiting on from the server
  828. udpClient.NeedAcks.Add(outgoingPacket);
  829. }
  830. }
  831. else
  832. {
  833. Interlocked.Increment(ref udpClient.PacketsResent);
  834. }
  835. #endregion Sequence Number Assignment
  836. // Stats tracking
  837. Interlocked.Increment(ref udpClient.PacketsSent);
  838. // Put the UDP payload on the wire
  839. AsyncBeginSend(buffer);
  840. // Keep track of when this packet was sent out (right now)
  841. outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue;
  842. }
  843. public override void PacketReceived(UDPPacketBuffer buffer)
  844. {
  845. // Debugging/Profiling
  846. //try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; }
  847. //catch (Exception) { }
  848. // m_log.DebugFormat(
  849. // "[LLUDPSERVER]: Packet received from {0} in {1}", buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
  850. LLUDPClient udpClient = null;
  851. Packet packet = null;
  852. int packetEnd = buffer.DataLength - 1;
  853. IPEndPoint endPoint = (IPEndPoint)buffer.RemoteEndPoint;
  854. #region Decoding
  855. if (buffer.DataLength < 7)
  856. {
  857. // m_log.WarnFormat(
  858. // "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
  859. // buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
  860. return; // Drop undersized packet
  861. }
  862. int headerLen = 7;
  863. if (buffer.Data[6] == 0xFF)
  864. {
  865. if (buffer.Data[7] == 0xFF)
  866. headerLen = 10;
  867. else
  868. headerLen = 8;
  869. }
  870. if (buffer.DataLength < headerLen)
  871. {
  872. // m_log.WarnFormat(
  873. // "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}",
  874. // buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
  875. return; // Malformed header
  876. }
  877. try
  878. {
  879. // packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
  880. // // Only allocate a buffer for zerodecoding if the packet is zerocoded
  881. // ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
  882. // If OpenSimUDPBase.UsePool == true (which is currently separate from the PacketPool) then we
  883. // assume that packet construction does not retain a reference to byte[] buffer.Data (instead, all
  884. // bytes are copied out).
  885. packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd,
  886. // Only allocate a buffer for zerodecoding if the packet is zerocoded
  887. ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
  888. }
  889. catch (MalformedDataException)
  890. {
  891. }
  892. catch (IndexOutOfRangeException)
  893. {
  894. // m_log.WarnFormat(
  895. // "[LLUDPSERVER]: Dropping short packet received from {0} in {1}",
  896. // buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
  897. return; // Drop short packet
  898. }
  899. catch (Exception e)
  900. {
  901. if (m_malformedCount < 100)
  902. m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
  903. m_malformedCount++;
  904. if ((m_malformedCount % 100000) == 0)
  905. m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount);
  906. }
  907. // Fail-safe check
  908. if (packet == null)
  909. {
  910. m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}:",
  911. buffer.DataLength, buffer.RemoteEndPoint);
  912. m_log.Error(Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
  913. return;
  914. }
  915. #endregion Decoding
  916. #region Packet to Client Mapping
  917. // UseCircuitCode handling
  918. if (packet.Type == PacketType.UseCircuitCode)
  919. {
  920. // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
  921. // buffer.
  922. object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
  923. Util.FireAndForget(HandleUseCircuitCode, array);
  924. return;
  925. }
  926. // Determine which agent this packet came from
  927. IClientAPI client;
  928. if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
  929. {
  930. //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
  931. return;
  932. }
  933. udpClient = ((LLClientView)client).UDPClient;
  934. if (!udpClient.IsConnected)
  935. return;
  936. #endregion Packet to Client Mapping
  937. // Stats tracking
  938. Interlocked.Increment(ref udpClient.PacketsReceived);
  939. int now = Environment.TickCount & Int32.MaxValue;
  940. udpClient.TickLastPacketReceived = now;
  941. #region ACK Receiving
  942. // Handle appended ACKs
  943. if (packet.Header.AppendedAcks && packet.Header.AckList != null)
  944. {
  945. // m_log.DebugFormat(
  946. // "[LLUDPSERVER]: Handling {0} appended acks from {1} in {2}",
  947. // packet.Header.AckList.Length, client.Name, m_scene.Name);
  948. for (int i = 0; i < packet.Header.AckList.Length; i++)
  949. udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent);
  950. }
  951. // Handle PacketAck packets
  952. if (packet.Type == PacketType.PacketAck)
  953. {
  954. PacketAckPacket ackPacket = (PacketAckPacket)packet;
  955. // m_log.DebugFormat(
  956. // "[LLUDPSERVER]: Handling {0} packet acks for {1} in {2}",
  957. // ackPacket.Packets.Length, client.Name, m_scene.Name);
  958. for (int i = 0; i < ackPacket.Packets.Length; i++)
  959. udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent);
  960. // We don't need to do anything else with PacketAck packets
  961. return;
  962. }
  963. #endregion ACK Receiving
  964. #region ACK Sending
  965. if (packet.Header.Reliable)
  966. {
  967. // m_log.DebugFormat(
  968. // "[LLUDPSERVER]: Adding ack request for {0} {1} from {2} in {3}",
  969. // packet.Type, packet.Header.Sequence, client.Name, m_scene.Name);
  970. udpClient.PendingAcks.Enqueue(packet.Header.Sequence);
  971. // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
  972. // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove
  973. // 2*MTU bytes from the value and send ACKs, and finally add the local value back to
  974. // client.BytesSinceLastACK. Lockless thread safety
  975. int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0);
  976. bytesSinceLastACK += buffer.DataLength;
  977. if (bytesSinceLastACK > LLUDPServer.MTU * 2)
  978. {
  979. bytesSinceLastACK -= LLUDPServer.MTU * 2;
  980. SendAcks(udpClient);
  981. }
  982. Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK);
  983. }
  984. #endregion ACK Sending
  985. #region Incoming Packet Accounting
  986. // Check the archive of received reliable packet IDs to see whether we already received this packet
  987. if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence))
  988. {
  989. if (packet.Header.Resent)
  990. m_log.DebugFormat(
  991. "[LLUDPSERVER]: Received a resend of already processed packet #{0}, type {1} from {2}",
  992. packet.Header.Sequence, packet.Type, client.Name);
  993. else
  994. m_log.WarnFormat(
  995. "[LLUDPSERVER]: Received a duplicate (not marked as resend) of packet #{0}, type {1} from {2}",
  996. packet.Header.Sequence, packet.Type, client.Name);
  997. // Avoid firing a callback twice for the same packet
  998. return;
  999. }
  1000. #endregion Incoming Packet Accounting
  1001. #region BinaryStats
  1002. LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
  1003. #endregion BinaryStats
  1004. #region Ping Check Handling
  1005. if (packet.Type == PacketType.StartPingCheck)
  1006. {
  1007. // m_log.DebugFormat("[LLUDPSERVER]: Handling ping from {0} in {1}", client.Name, m_scene.Name);
  1008. // We don't need to do anything else with ping checks
  1009. StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
  1010. CompletePing(udpClient, startPing.PingID.PingID);
  1011. if ((Environment.TickCount - m_elapsedMSSinceLastStatReport) >= 3000)
  1012. {
  1013. udpClient.SendPacketStats();
  1014. m_elapsedMSSinceLastStatReport = Environment.TickCount;
  1015. }
  1016. return;
  1017. }
  1018. else if (packet.Type == PacketType.CompletePingCheck)
  1019. {
  1020. // We don't currently track client ping times
  1021. return;
  1022. }
  1023. #endregion Ping Check Handling
  1024. IncomingPacket incomingPacket;
  1025. // Inbox insertion
  1026. if (UsePools)
  1027. {
  1028. incomingPacket = m_incomingPacketPool.GetObject();
  1029. incomingPacket.Client = (LLClientView)client;
  1030. incomingPacket.Packet = packet;
  1031. }
  1032. else
  1033. {
  1034. incomingPacket = new IncomingPacket((LLClientView)client, packet);
  1035. }
  1036. packetInbox.Enqueue(incomingPacket);
  1037. }
  1038. #region BinaryStats
  1039. public class PacketLogger
  1040. {
  1041. public DateTime StartTime;
  1042. public string Path = null;
  1043. public System.IO.BinaryWriter Log = null;
  1044. }
  1045. public static PacketLogger PacketLog;
  1046. protected static bool m_shouldCollectStats = false;
  1047. // Number of seconds to log for
  1048. static TimeSpan binStatsMaxFilesize = TimeSpan.FromSeconds(300);
  1049. static object binStatsLogLock = new object();
  1050. static string binStatsDir = "";
  1051. public static void LogPacketHeader(bool incoming, uint circuit, byte flags, PacketType packetType, ushort size)
  1052. {
  1053. if (!m_shouldCollectStats) return;
  1054. // Binary logging format is TTTTTTTTCCCCFPPPSS, T=Time, C=Circuit, F=Flags, P=PacketType, S=size
  1055. // Put the incoming bit into the least significant bit of the flags byte
  1056. if (incoming)
  1057. flags |= 0x01;
  1058. else
  1059. flags &= 0xFE;
  1060. // Put the flags byte into the most significant bits of the type integer
  1061. uint type = (uint)packetType;
  1062. type |= (uint)flags << 24;
  1063. // m_log.Debug("1 LogPacketHeader(): Outside lock");
  1064. lock (binStatsLogLock)
  1065. {
  1066. DateTime now = DateTime.Now;
  1067. // m_log.Debug("2 LogPacketHeader(): Inside lock. now is " + now.Ticks);
  1068. try
  1069. {
  1070. if (PacketLog == null || (now > PacketLog.StartTime + binStatsMaxFilesize))
  1071. {
  1072. if (PacketLog != null && PacketLog.Log != null)
  1073. {
  1074. PacketLog.Log.Close();
  1075. }
  1076. // First log file or time has expired, start writing to a new log file
  1077. PacketLog = new PacketLogger();
  1078. PacketLog.StartTime = now;
  1079. PacketLog.Path = (binStatsDir.Length > 0 ? binStatsDir + System.IO.Path.DirectorySeparatorChar.ToString() : "")
  1080. + String.Format("packets-{0}.log", now.ToString("yyyyMMddHHmmss"));
  1081. PacketLog.Log = new BinaryWriter(File.Open(PacketLog.Path, FileMode.Append, FileAccess.Write));
  1082. }
  1083. // Serialize the data
  1084. byte[] output = new byte[18];
  1085. Buffer.BlockCopy(BitConverter.GetBytes(now.Ticks), 0, output, 0, 8);
  1086. Buffer.BlockCopy(BitConverter.GetBytes(circuit), 0, output, 8, 4);
  1087. Buffer.BlockCopy(BitConverter.GetBytes(type), 0, output, 12, 4);
  1088. Buffer.BlockCopy(BitConverter.GetBytes(size), 0, output, 16, 2);
  1089. // Write the serialized data to disk
  1090. if (PacketLog != null && PacketLog.Log != null)
  1091. PacketLog.Log.Write(output);
  1092. }
  1093. catch (Exception ex)
  1094. {
  1095. m_log.Error("Packet statistics gathering failed: " + ex.Message, ex);
  1096. if (PacketLog.Log != null)
  1097. {
  1098. PacketLog.Log.Close();
  1099. }
  1100. PacketLog = null;
  1101. }
  1102. }
  1103. }
  1104. #endregion BinaryStats
  1105. private void HandleUseCircuitCode(object o)
  1106. {
  1107. IPEndPoint endPoint = null;
  1108. IClientAPI client = null;
  1109. try
  1110. {
  1111. // DateTime startTime = DateTime.Now;
  1112. object[] array = (object[])o;
  1113. endPoint = (IPEndPoint)array[0];
  1114. UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
  1115. m_log.DebugFormat(
  1116. "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}",
  1117. uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, endPoint);
  1118. AuthenticateResponse sessionInfo;
  1119. if (IsClientAuthorized(uccp, out sessionInfo))
  1120. {
  1121. // Begin the process of adding the client to the simulator
  1122. client
  1123. = AddClient(
  1124. uccp.CircuitCode.Code,
  1125. uccp.CircuitCode.ID,
  1126. uccp.CircuitCode.SessionID,
  1127. endPoint,
  1128. sessionInfo);
  1129. // Send ack straight away to let the viewer know that the connection is active.
  1130. // The client will be null if it already exists (e.g. if on a region crossing the client sends a use
  1131. // circuit code to the existing child agent. This is not particularly obvious.
  1132. SendAckImmediate(endPoint, uccp.Header.Sequence);
  1133. // We only want to send initial data to new clients, not ones which are being converted from child to root.
  1134. if (client != null)
  1135. client.SceneAgent.SendInitialDataToMe();
  1136. }
  1137. else
  1138. {
  1139. // Don't create clients for unauthorized requesters.
  1140. m_log.WarnFormat(
  1141. "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
  1142. uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
  1143. }
  1144. // m_log.DebugFormat(
  1145. // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms",
  1146. // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds);
  1147. }
  1148. catch (Exception e)
  1149. {
  1150. m_log.ErrorFormat(
  1151. "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
  1152. endPoint != null ? endPoint.ToString() : "n/a",
  1153. client != null ? client.Name : "unknown",
  1154. client != null ? client.AgentId.ToString() : "unknown",
  1155. e.Message,
  1156. e.StackTrace);
  1157. }
  1158. }
  1159. /// <summary>
  1160. /// Send an ack immediately to the given endpoint.
  1161. /// </summary>
  1162. /// <remarks>
  1163. /// FIXME: Might be possible to use SendPacketData() like everything else, but this will require refactoring so
  1164. /// that we can obtain the UDPClient easily at this point.
  1165. /// </remarks>
  1166. /// <param name="remoteEndpoint"></param>
  1167. /// <param name="sequenceNumber"></param>
  1168. private void SendAckImmediate(IPEndPoint remoteEndpoint, uint sequenceNumber)
  1169. {
  1170. PacketAckPacket ack = new PacketAckPacket();
  1171. ack.Header.Reliable = false;
  1172. ack.Packets = new PacketAckPacket.PacketsBlock[1];
  1173. ack.Packets[0] = new PacketAckPacket.PacketsBlock();
  1174. ack.Packets[0].ID = sequenceNumber;
  1175. SendAckImmediate(remoteEndpoint, ack);
  1176. }
  1177. public virtual void SendAckImmediate(IPEndPoint remoteEndpoint, PacketAckPacket ack)
  1178. {
  1179. byte[] packetData = ack.ToBytes();
  1180. int length = packetData.Length;
  1181. UDPPacketBuffer buffer = new UDPPacketBuffer(remoteEndpoint, length);
  1182. buffer.DataLength = length;
  1183. Buffer.BlockCopy(packetData, 0, buffer.Data, 0, length);
  1184. AsyncBeginSend(buffer);
  1185. }
  1186. private bool IsClientAuthorized(UseCircuitCodePacket useCircuitCode, out AuthenticateResponse sessionInfo)
  1187. {
  1188. UUID agentID = useCircuitCode.CircuitCode.ID;
  1189. UUID sessionID = useCircuitCode.CircuitCode.SessionID;
  1190. uint circuitCode = useCircuitCode.CircuitCode.Code;
  1191. sessionInfo = m_circuitManager.AuthenticateSession(sessionID, agentID, circuitCode);
  1192. return sessionInfo.Authorised;
  1193. }
  1194. /// <summary>
  1195. /// Add a client.
  1196. /// </summary>
  1197. /// <param name="circuitCode"></param>
  1198. /// <param name="agentID"></param>
  1199. /// <param name="sessionID"></param>
  1200. /// <param name="remoteEndPoint"></param>
  1201. /// <param name="sessionInfo"></param>
  1202. /// <returns>The client if it was added. Null if the client already existed.</returns>
  1203. protected virtual IClientAPI AddClient(
  1204. uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
  1205. {
  1206. IClientAPI client = null;
  1207. // We currently synchronize this code across the whole scene to avoid issues such as
  1208. // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done
  1209. // consistently, this lock could probably be removed.
  1210. lock (this)
  1211. {
  1212. if (!m_scene.TryGetClient(agentID, out client))
  1213. {
  1214. LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
  1215. client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
  1216. client.OnLogout += LogoutHandler;
  1217. ((LLClientView)client).DisableFacelights = m_disableFacelights;
  1218. client.Start();
  1219. }
  1220. }
  1221. return client;
  1222. }
  1223. /// <summary>
  1224. /// Deactivates the client if we don't receive any packets within a certain amount of time (default 60 seconds).
  1225. /// </summary>
  1226. /// <remarks>
  1227. /// If a connection is active then we will always receive packets even if nothing else is happening, due to
  1228. /// regular client pings.
  1229. /// </remarks>
  1230. /// <param name='client'></param>
  1231. private void DeactivateClientDueToTimeout(LLClientView client)
  1232. {
  1233. lock (client.CloseSyncLock)
  1234. {
  1235. m_log.WarnFormat(
  1236. "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}",
  1237. client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName);
  1238. StatsManager.SimExtraStats.AddAbnormalClientThreadTermination();
  1239. if (!client.SceneAgent.IsChildAgent)
  1240. client.Kick("Simulator logged you out due to connection timeout");
  1241. client.CloseWithoutChecks();
  1242. }
  1243. }
  1244. private void IncomingPacketHandler()
  1245. {
  1246. // Set this culture for the thread that incoming packets are received
  1247. // on to en-US to avoid number parsing issues
  1248. Culture.SetCurrentCulture();
  1249. while (IsRunningInbound)
  1250. {
  1251. try
  1252. {
  1253. IncomingPacket incomingPacket = null;
  1254. // HACK: This is a test to try and rate limit packet handling on Mono.
  1255. // If it works, a more elegant solution can be devised
  1256. if (Util.FireAndForgetCount() < 2)
  1257. {
  1258. //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping");
  1259. Thread.Sleep(30);
  1260. }
  1261. if (packetInbox.Dequeue(100, ref incomingPacket))
  1262. {
  1263. ProcessInPacket(incomingPacket);//, incomingPacket); Util.FireAndForget(ProcessInPacket, incomingPacket);
  1264. if (UsePools)
  1265. m_incomingPacketPool.ReturnObject(incomingPacket);
  1266. }
  1267. }
  1268. catch (Exception ex)
  1269. {
  1270. m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex);
  1271. }
  1272. Watchdog.UpdateThread();
  1273. }
  1274. if (packetInbox.Count > 0)
  1275. m_log.Warn("[LLUDPSERVER]: IncomingPacketHandler is shutting down, dropping " + packetInbox.Count + " packets");
  1276. packetInbox.Clear();
  1277. Watchdog.RemoveThread();
  1278. }
  1279. private void OutgoingPacketHandler()
  1280. {
  1281. // Set this culture for the thread that outgoing packets are sent
  1282. // on to en-US to avoid number parsing issues
  1283. Culture.SetCurrentCulture();
  1284. // Typecast the function to an Action<IClientAPI> once here to avoid allocating a new
  1285. // Action generic every round
  1286. Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
  1287. while (base.IsRunningOutbound)
  1288. {
  1289. try
  1290. {
  1291. m_packetSent = false;
  1292. #region Update Timers
  1293. m_resendUnacked = false;
  1294. m_sendAcks = false;
  1295. m_sendPing = false;
  1296. // Update elapsed time
  1297. int thisTick = Environment.TickCount & Int32.MaxValue;
  1298. if (m_tickLastOutgoingPacketHandler > thisTick)
  1299. m_elapsedMSOutgoingPacketHandler += ((Int32.MaxValue - m_tickLastOutgoingPacketHandler) + thisTick);
  1300. else
  1301. m_elapsedMSOutgoingPacketHandler += (thisTick - m_tickLastOutgoingPacketHandler);
  1302. m_tickLastOutgoingPacketHandler = thisTick;
  1303. // Check for pending outgoing resends every 100ms
  1304. if (m_elapsedMSOutgoingPacketHandler >= 100)
  1305. {
  1306. m_resendUnacked = true;
  1307. m_elapsedMSOutgoingPacketHandler = 0;
  1308. m_elapsed100MSOutgoingPacketHandler += 1;
  1309. }
  1310. // Check for pending outgoing ACKs every 500ms
  1311. if (m_elapsed100MSOutgoingPacketHandler >= 5)
  1312. {
  1313. m_sendAcks = true;
  1314. m_elapsed100MSOutgoingPacketHandler = 0;
  1315. m_elapsed500MSOutgoingPacketHandler += 1;
  1316. }
  1317. // Send pings to clients every 5000ms
  1318. if (m_elapsed500MSOutgoingPacketHandler >= 10)
  1319. {
  1320. m_sendPing = true;
  1321. m_elapsed500MSOutgoingPacketHandler = 0;
  1322. }
  1323. #endregion Update Timers
  1324. // Use this for emergency monitoring -- bug hunting
  1325. //if (m_scene.EmergencyMonitoring)
  1326. // clientPacketHandler = MonitoredClientOutgoingPacketHandler;
  1327. //else
  1328. // clientPacketHandler = ClientOutgoingPacketHandler;
  1329. // Handle outgoing packets, resends, acknowledgements, and pings for each
  1330. // client. m_packetSent will be set to true if a packet is sent
  1331. m_scene.ForEachClient(clientPacketHandler);
  1332. m_currentOutgoingClient = null;
  1333. // If nothing was sent, sleep for the minimum amount of time before a
  1334. // token bucket could get more tokens
  1335. if (!m_packetSent)
  1336. Thread.Sleep((int)TickCountResolution);
  1337. Watchdog.UpdateThread();
  1338. }
  1339. catch (Exception ex)
  1340. {
  1341. m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler loop threw an exception: " + ex.Message, ex);
  1342. }
  1343. }
  1344. Watchdog.RemoveThread();
  1345. }
  1346. protected void ClientOutgoingPacketHandler(IClientAPI client)
  1347. {
  1348. m_currentOutgoingClient = client;
  1349. try
  1350. {
  1351. if (client is LLClientView)
  1352. {
  1353. LLClientView llClient = (LLClientView)client;
  1354. LLUDPClient udpClient = llClient.UDPClient;
  1355. if (udpClient.IsConnected)
  1356. {
  1357. if (m_resendUnacked)
  1358. HandleUnacked(llClient);
  1359. if (m_sendAcks)
  1360. SendAcks(udpClient);
  1361. if (m_sendPing)
  1362. SendPing(udpClient);
  1363. // Dequeue any outgoing packets that are within the throttle limits
  1364. if (udpClient.DequeueOutgoing())
  1365. m_packetSent = true;
  1366. }
  1367. }
  1368. }
  1369. catch (Exception ex)
  1370. {
  1371. m_log.Error(
  1372. string.Format("[LLUDPSERVER]: OutgoingPacketHandler iteration for {0} threw ", client.Name), ex);
  1373. }
  1374. }
  1375. #region Emergency Monitoring
  1376. // Alternative packet handler fuull of instrumentation
  1377. // Handy for hunting bugs
  1378. private Stopwatch watch1 = new Stopwatch();
  1379. private Stopwatch watch2 = new Stopwatch();
  1380. private float avgProcessingTicks = 0;
  1381. private float avgResendUnackedTicks = 0;
  1382. private float avgSendAcksTicks = 0;
  1383. private float avgSendPingTicks = 0;
  1384. private float avgDequeueTicks = 0;
  1385. private long nticks = 0;
  1386. private long nticksUnack = 0;
  1387. private long nticksAck = 0;
  1388. private long nticksPing = 0;
  1389. private int npacksSent = 0;
  1390. private int npackNotSent = 0;
  1391. /// <summary>
  1392. /// Number of inbound packets processed since startup.
  1393. /// </summary>
  1394. public long IncomingPacketsProcessed { get; private set; }
  1395. private void MonitoredClientOutgoingPacketHandler(IClientAPI client)
  1396. {
  1397. nticks++;
  1398. watch1.Start();
  1399. m_currentOutgoingClient = client;
  1400. try
  1401. {
  1402. if (client is LLClientView)
  1403. {
  1404. LLClientView llClient = (LLClientView)client;
  1405. LLUDPClient udpClient = llClient.UDPClient;
  1406. if (udpClient.IsConnected)
  1407. {
  1408. if (m_resendUnacked)
  1409. {
  1410. nticksUnack++;
  1411. watch2.Start();
  1412. HandleUnacked(llClient);
  1413. watch2.Stop();
  1414. avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack);
  1415. watch2.Reset();
  1416. }
  1417. if (m_sendAcks)
  1418. {
  1419. nticksAck++;
  1420. watch2.Start();
  1421. SendAcks(udpClient);
  1422. watch2.Stop();
  1423. avgSendAcksTicks = (nticksAck - 1) / (float)nticksAck * avgSendAcksTicks + (watch2.ElapsedTicks / (float)nticksAck);
  1424. watch2.Reset();
  1425. }
  1426. if (m_sendPing)
  1427. {
  1428. nticksPing++;
  1429. watch2.Start();
  1430. SendPing(udpClient);
  1431. watch2.Stop();
  1432. avgSendPingTicks = (nticksPing - 1) / (float)nticksPing * avgSendPingTicks + (watch2.ElapsedTicks / (float)nticksPing);
  1433. watch2.Reset();
  1434. }
  1435. watch2.Start();
  1436. // Dequeue any outgoing packets that are within the throttle limits
  1437. if (udpClient.DequeueOutgoing())
  1438. {
  1439. m_packetSent = true;
  1440. npacksSent++;
  1441. }
  1442. else
  1443. {
  1444. npackNotSent++;
  1445. }
  1446. watch2.Stop();
  1447. avgDequeueTicks = (nticks - 1) / (float)nticks * avgDequeueTicks + (watch2.ElapsedTicks / (float)nticks);
  1448. watch2.Reset();
  1449. }
  1450. else
  1451. {
  1452. m_log.WarnFormat("[LLUDPSERVER]: Client is not connected");
  1453. }
  1454. }
  1455. }
  1456. catch (Exception ex)
  1457. {
  1458. m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name +
  1459. " threw an exception: " + ex.Message, ex);
  1460. }
  1461. watch1.Stop();
  1462. avgProcessingTicks = (nticks - 1) / (float)nticks * avgProcessingTicks + (watch1.ElapsedTicks / (float)nticks);
  1463. watch1.Reset();
  1464. // reuse this -- it's every ~100ms
  1465. if (m_scene.EmergencyMonitoring && nticks % 100 == 0)
  1466. {
  1467. 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})",
  1468. avgProcessingTicks, avgResendUnackedTicks, avgSendAcksTicks, avgSendPingTicks, avgDequeueTicks, TickCountResolution, npacksSent, npackNotSent);
  1469. npackNotSent = npacksSent = 0;
  1470. }
  1471. }
  1472. #endregion
  1473. private void ProcessInPacket(IncomingPacket incomingPacket)
  1474. {
  1475. Packet packet = incomingPacket.Packet;
  1476. LLClientView client = incomingPacket.Client;
  1477. if (client.IsActive)
  1478. {
  1479. m_currentIncomingClient = client;
  1480. try
  1481. {
  1482. // Process this packet
  1483. client.ProcessInPacket(packet);
  1484. }
  1485. catch (ThreadAbortException)
  1486. {
  1487. // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down
  1488. m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server");
  1489. Stop();
  1490. }
  1491. catch (Exception e)
  1492. {
  1493. // Don't let a failure in an individual client thread crash the whole sim.
  1494. m_log.Error(
  1495. string.Format(
  1496. "[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw ",
  1497. client.Name, packet.Type),
  1498. e);
  1499. }
  1500. finally
  1501. {
  1502. m_currentIncomingClient = null;
  1503. }
  1504. }
  1505. else
  1506. {
  1507. m_log.DebugFormat(
  1508. "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}",
  1509. packet.Type, client.Name, m_scene.RegionInfo.RegionName);
  1510. }
  1511. IncomingPacketsProcessed++;
  1512. }
  1513. protected void LogoutHandler(IClientAPI client)
  1514. {
  1515. client.SendLogoutPacket();
  1516. if (!client.IsLoggingOut)
  1517. {
  1518. client.IsLoggingOut = true;
  1519. client.Close();
  1520. }
  1521. }
  1522. }
  1523. }