LLUDPServer.cs 78 KB

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