LLUDPServer.cs 86 KB

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