LLPacketQueue.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  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 OpenSim 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.Threading;
  30. using System.Timers;
  31. using OpenMetaverse;
  32. using OpenMetaverse.Packets;
  33. using OpenSim.Framework;
  34. using OpenSim.Framework.Statistics;
  35. using OpenSim.Framework.Statistics.Interfaces;
  36. using OpenSim.Region.ClientStack;
  37. using Timer=System.Timers.Timer;
  38. namespace OpenSim.Region.ClientStack.LindenUDP
  39. {
  40. public class LLPacketQueue : IPullStatsProvider
  41. {
  42. private static readonly log4net.ILog m_log
  43. = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
  44. /// <summary>
  45. /// Is queueing enabled at all?
  46. /// </summary>
  47. private bool m_enabled = true;
  48. private OpenSim.Framework.BlockingQueue<LLQueItem> SendQueue;
  49. private Queue<LLQueItem> IncomingPacketQueue;
  50. private Queue<LLQueItem> OutgoingPacketQueue;
  51. private Queue<LLQueItem> ResendOutgoingPacketQueue;
  52. private Queue<LLQueItem> LandOutgoingPacketQueue;
  53. private Queue<LLQueItem> WindOutgoingPacketQueue;
  54. private Queue<LLQueItem> CloudOutgoingPacketQueue;
  55. private Queue<LLQueItem> TaskOutgoingPacketQueue;
  56. private Queue<LLQueItem> TaskLowpriorityPacketQueue;
  57. private Queue<LLQueItem> TextureOutgoingPacketQueue;
  58. private Queue<LLQueItem> AssetOutgoingPacketQueue;
  59. // private Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>();
  60. // private Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>();
  61. // All throttle times and number of bytes are calculated by dividing by this value
  62. // This value also determines how many times per throttletimems the timer will run
  63. // If throttleimems is 1000 ms, then the timer will fire every 1000/7 milliseconds
  64. private int throttleTimeDivisor = 7;
  65. private int throttletimems = 1000;
  66. private LLPacketThrottle ResendThrottle;
  67. private LLPacketThrottle LandThrottle;
  68. private LLPacketThrottle WindThrottle;
  69. private LLPacketThrottle CloudThrottle;
  70. private LLPacketThrottle TaskThrottle;
  71. private LLPacketThrottle AssetThrottle;
  72. private LLPacketThrottle TextureThrottle;
  73. private LLPacketThrottle TotalThrottle;
  74. // private long LastThrottle;
  75. // private long ThrottleInterval;
  76. private Timer throttleTimer;
  77. private UUID m_agentId;
  78. public LLPacketQueue(UUID agentId, ClientStackUserSettings userSettings)
  79. {
  80. // While working on this, the BlockingQueue had me fooled for a bit.
  81. // The Blocking queue causes the thread to stop until there's something
  82. // in it to process. it's an on-purpose threadlock though because
  83. // without it, the clientloop will suck up all sim resources.
  84. SendQueue = new OpenSim.Framework.BlockingQueue<LLQueItem>();
  85. IncomingPacketQueue = new Queue<LLQueItem>();
  86. OutgoingPacketQueue = new Queue<LLQueItem>();
  87. ResendOutgoingPacketQueue = new Queue<LLQueItem>();
  88. LandOutgoingPacketQueue = new Queue<LLQueItem>();
  89. WindOutgoingPacketQueue = new Queue<LLQueItem>();
  90. CloudOutgoingPacketQueue = new Queue<LLQueItem>();
  91. TaskOutgoingPacketQueue = new Queue<LLQueItem>();
  92. TaskLowpriorityPacketQueue = new Queue<LLQueItem>();
  93. TextureOutgoingPacketQueue = new Queue<LLQueItem>();
  94. AssetOutgoingPacketQueue = new Queue<LLQueItem>();
  95. // Set up the throttle classes (min, max, current) in bits per second
  96. ResendThrottle = new LLPacketThrottle(5000, 100000, 16000, userSettings.ClientThrottleMultipler);
  97. LandThrottle = new LLPacketThrottle(1000, 100000, 2000, userSettings.ClientThrottleMultipler);
  98. WindThrottle = new LLPacketThrottle(0, 100000, 0, userSettings.ClientThrottleMultipler);
  99. CloudThrottle = new LLPacketThrottle(0, 100000, 0, userSettings.ClientThrottleMultipler);
  100. TaskThrottle = new LLPacketThrottle(1000, 800000, 3000, userSettings.ClientThrottleMultipler);
  101. AssetThrottle = new LLPacketThrottle(1000, 800000, 1000, userSettings.ClientThrottleMultipler);
  102. TextureThrottle = new LLPacketThrottle(1000, 800000, 4000, userSettings.ClientThrottleMultipler);
  103. // Total Throttle trumps all - it is the number of bits in total that are allowed to go out per second.
  104. ThrottleSettings totalThrottleSettings = userSettings.TotalThrottleSettings;
  105. if (null == totalThrottleSettings)
  106. {
  107. totalThrottleSettings = new ThrottleSettings(0, 1500000, 28000);
  108. }
  109. TotalThrottle
  110. = new LLPacketThrottle(
  111. totalThrottleSettings.Min, totalThrottleSettings.Max, totalThrottleSettings.Current,
  112. userSettings.ClientThrottleMultipler);
  113. throttleTimer = new Timer((int) (throttletimems/throttleTimeDivisor));
  114. throttleTimer.Elapsed += ThrottleTimerElapsed;
  115. throttleTimer.Start();
  116. // TIMERS needed for this
  117. // LastThrottle = DateTime.Now.Ticks;
  118. // ThrottleInterval = (long)(throttletimems/throttleTimeDivisor);
  119. m_agentId = agentId;
  120. if (StatsManager.SimExtraStats != null)
  121. {
  122. StatsManager.SimExtraStats.RegisterPacketQueueStatsProvider(m_agentId, this);
  123. }
  124. }
  125. /* STANDARD QUEUE MANIPULATION INTERFACES */
  126. public void Enqueue(LLQueItem item)
  127. {
  128. if (!m_enabled)
  129. {
  130. return;
  131. }
  132. // We could micro lock, but that will tend to actually
  133. // probably be worse than just synchronizing on SendQueue
  134. if (item == null)
  135. {
  136. SendQueue.Enqueue(item);
  137. return;
  138. }
  139. if (item.Incoming)
  140. {
  141. SendQueue.PriorityEnqueue(item);
  142. return;
  143. }
  144. lock (this)
  145. {
  146. switch (item.throttleType & ThrottleOutPacketType.TypeMask)
  147. {
  148. case ThrottleOutPacketType.Resend:
  149. ThrottleCheck(ref ResendThrottle, ref ResendOutgoingPacketQueue, item);
  150. break;
  151. case ThrottleOutPacketType.Texture:
  152. ThrottleCheck(ref TextureThrottle, ref TextureOutgoingPacketQueue, item);
  153. break;
  154. case ThrottleOutPacketType.Task:
  155. if ((item.throttleType & ThrottleOutPacketType.LowPriority) != 0)
  156. ThrottleCheck(ref TaskThrottle, ref TaskLowpriorityPacketQueue, item);
  157. else
  158. ThrottleCheck(ref TaskThrottle, ref TaskOutgoingPacketQueue, item);
  159. break;
  160. case ThrottleOutPacketType.Land:
  161. ThrottleCheck(ref LandThrottle, ref LandOutgoingPacketQueue, item);
  162. break;
  163. case ThrottleOutPacketType.Asset:
  164. ThrottleCheck(ref AssetThrottle, ref AssetOutgoingPacketQueue, item);
  165. break;
  166. case ThrottleOutPacketType.Cloud:
  167. ThrottleCheck(ref CloudThrottle, ref CloudOutgoingPacketQueue, item);
  168. break;
  169. case ThrottleOutPacketType.Wind:
  170. ThrottleCheck(ref WindThrottle, ref WindOutgoingPacketQueue, item);
  171. break;
  172. default:
  173. // Acknowledgements and other such stuff should go directly to the blocking Queue
  174. // Throttling them may and likely 'will' be problematic
  175. SendQueue.PriorityEnqueue(item);
  176. break;
  177. }
  178. }
  179. }
  180. public LLQueItem Dequeue()
  181. {
  182. return SendQueue.Dequeue();
  183. }
  184. public void Flush()
  185. {
  186. lock (this)
  187. {
  188. while (PacketsWaiting())
  189. {
  190. //Now comes the fun part.. we dump all our elements into m_packetQueue that we've saved up.
  191. if (ResendOutgoingPacketQueue.Count > 0)
  192. {
  193. SendQueue.Enqueue(ResendOutgoingPacketQueue.Dequeue());
  194. }
  195. if (LandOutgoingPacketQueue.Count > 0)
  196. {
  197. SendQueue.Enqueue(LandOutgoingPacketQueue.Dequeue());
  198. }
  199. if (WindOutgoingPacketQueue.Count > 0)
  200. {
  201. SendQueue.Enqueue(WindOutgoingPacketQueue.Dequeue());
  202. }
  203. if (CloudOutgoingPacketQueue.Count > 0)
  204. {
  205. SendQueue.Enqueue(CloudOutgoingPacketQueue.Dequeue());
  206. }
  207. if (TaskOutgoingPacketQueue.Count > 0)
  208. {
  209. SendQueue.PriorityEnqueue(TaskOutgoingPacketQueue.Dequeue());
  210. }
  211. if (TaskLowpriorityPacketQueue.Count > 0)
  212. {
  213. SendQueue.Enqueue(TaskLowpriorityPacketQueue.Dequeue());
  214. }
  215. if (TextureOutgoingPacketQueue.Count > 0)
  216. {
  217. SendQueue.Enqueue(TextureOutgoingPacketQueue.Dequeue());
  218. }
  219. if (AssetOutgoingPacketQueue.Count > 0)
  220. {
  221. SendQueue.Enqueue(AssetOutgoingPacketQueue.Dequeue());
  222. }
  223. }
  224. // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets");
  225. }
  226. }
  227. public void WipeClean()
  228. {
  229. m_log.Info("[PACKETQUEUE] Wiping Packet Queues Clean");
  230. lock (this)
  231. {
  232. ResendOutgoingPacketQueue.Clear();
  233. LandOutgoingPacketQueue.Clear();
  234. WindOutgoingPacketQueue.Clear();
  235. CloudOutgoingPacketQueue.Clear();
  236. TaskOutgoingPacketQueue.Clear();
  237. TaskLowpriorityPacketQueue.Clear();
  238. TextureOutgoingPacketQueue.Clear();
  239. AssetOutgoingPacketQueue.Clear();
  240. SendQueue.Clear();
  241. }
  242. }
  243. public void Close()
  244. {
  245. m_log.Info("[PACKETQUEUE] Close called");
  246. Flush();
  247. WipeClean(); // I'm sure there's a dirty joke in here somewhere. -AFrisby
  248. m_enabled = false;
  249. throttleTimer.Stop();
  250. if (StatsManager.SimExtraStats != null)
  251. {
  252. StatsManager.SimExtraStats.DeregisterPacketQueueStatsProvider(m_agentId);
  253. }
  254. }
  255. private void ResetCounters()
  256. {
  257. ResendThrottle.Reset();
  258. LandThrottle.Reset();
  259. WindThrottle.Reset();
  260. CloudThrottle.Reset();
  261. TaskThrottle.Reset();
  262. AssetThrottle.Reset();
  263. TextureThrottle.Reset();
  264. TotalThrottle.Reset();
  265. }
  266. private bool PacketsWaiting()
  267. {
  268. return (ResendOutgoingPacketQueue.Count > 0 ||
  269. LandOutgoingPacketQueue.Count > 0 ||
  270. WindOutgoingPacketQueue.Count > 0 ||
  271. CloudOutgoingPacketQueue.Count > 0 ||
  272. TaskOutgoingPacketQueue.Count > 0 ||
  273. TaskLowpriorityPacketQueue.Count > 0 ||
  274. AssetOutgoingPacketQueue.Count > 0 ||
  275. TextureOutgoingPacketQueue.Count > 0);
  276. }
  277. public void ProcessThrottle()
  278. {
  279. // I was considering this.. Will an event fire if the thread it's on is blocked?
  280. // Then I figured out.. it doesn't really matter.. because this thread won't be blocked for long
  281. // The General overhead of the UDP protocol gets sent to the queue un-throttled by this
  282. // so This'll pick up about around the right time.
  283. int MaxThrottleLoops = 4550; // 50*7 packets can be dequeued at once.
  284. int throttleLoops = 0;
  285. // We're going to dequeue all of the saved up packets until
  286. // we've hit the throttle limit or there's no more packets to send
  287. lock (this)
  288. {
  289. // this variable will be true if there was work done in the last execution of the
  290. // loop, since each pass through the loop checks the queue length, we no longer
  291. // need the check on entering the loop
  292. bool qchanged = true;
  293. ResetCounters();
  294. // m_log.Info("[THROTTLE]: Entering Throttle");
  295. while (TotalThrottle.UnderLimit() && qchanged && throttleLoops <= MaxThrottleLoops)
  296. {
  297. qchanged = false; // We will break out of the loop if no work was accomplished
  298. throttleLoops++;
  299. //Now comes the fun part.. we dump all our elements into m_packetQueue that we've saved up.
  300. if ((ResendOutgoingPacketQueue.Count > 0) && ResendThrottle.UnderLimit())
  301. {
  302. LLQueItem qpack = ResendOutgoingPacketQueue.Dequeue();
  303. SendQueue.Enqueue(qpack);
  304. TotalThrottle.AddBytes(qpack.Length);
  305. ResendThrottle.AddBytes(qpack.Length);
  306. qchanged = true;
  307. }
  308. if ((LandOutgoingPacketQueue.Count > 0) && LandThrottle.UnderLimit())
  309. {
  310. LLQueItem qpack = LandOutgoingPacketQueue.Dequeue();
  311. SendQueue.Enqueue(qpack);
  312. TotalThrottle.AddBytes(qpack.Length);
  313. LandThrottle.AddBytes(qpack.Length);
  314. qchanged = true;
  315. }
  316. if ((WindOutgoingPacketQueue.Count > 0) && WindThrottle.UnderLimit())
  317. {
  318. LLQueItem qpack = WindOutgoingPacketQueue.Dequeue();
  319. SendQueue.Enqueue(qpack);
  320. TotalThrottle.AddBytes(qpack.Length);
  321. WindThrottle.AddBytes(qpack.Length);
  322. qchanged = true;
  323. }
  324. if ((CloudOutgoingPacketQueue.Count > 0) && CloudThrottle.UnderLimit())
  325. {
  326. LLQueItem qpack = CloudOutgoingPacketQueue.Dequeue();
  327. SendQueue.Enqueue(qpack);
  328. TotalThrottle.AddBytes(qpack.Length);
  329. CloudThrottle.AddBytes(qpack.Length);
  330. qchanged = true;
  331. }
  332. if ((TaskOutgoingPacketQueue.Count > 0 || TaskLowpriorityPacketQueue.Count > 0) && TaskThrottle.UnderLimit())
  333. {
  334. LLQueItem qpack;
  335. if (TaskOutgoingPacketQueue.Count > 0)
  336. {
  337. qpack = TaskOutgoingPacketQueue.Dequeue();
  338. SendQueue.PriorityEnqueue(qpack);
  339. }
  340. else
  341. {
  342. qpack = TaskLowpriorityPacketQueue.Dequeue();
  343. SendQueue.Enqueue(qpack);
  344. }
  345. TotalThrottle.AddBytes(qpack.Length);
  346. TaskThrottle.AddBytes(qpack.Length);
  347. qchanged = true;
  348. }
  349. if ((TextureOutgoingPacketQueue.Count > 0) && TextureThrottle.UnderLimit())
  350. {
  351. LLQueItem qpack = TextureOutgoingPacketQueue.Dequeue();
  352. SendQueue.Enqueue(qpack);
  353. TotalThrottle.AddBytes(qpack.Length);
  354. TextureThrottle.AddBytes(qpack.Length);
  355. qchanged = true;
  356. }
  357. if ((AssetOutgoingPacketQueue.Count > 0) && AssetThrottle.UnderLimit())
  358. {
  359. LLQueItem qpack = AssetOutgoingPacketQueue.Dequeue();
  360. SendQueue.Enqueue(qpack);
  361. TotalThrottle.AddBytes(qpack.Length);
  362. AssetThrottle.AddBytes(qpack.Length);
  363. qchanged = true;
  364. }
  365. }
  366. // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets");
  367. }
  368. }
  369. private void ThrottleTimerElapsed(object sender, ElapsedEventArgs e)
  370. {
  371. // just to change the signature, and that ProcessThrottle
  372. // will be used elsewhere possibly
  373. ProcessThrottle();
  374. }
  375. private void ThrottleCheck(ref LLPacketThrottle throttle, ref Queue<LLQueItem> q, LLQueItem item)
  376. {
  377. // The idea.. is if the packet throttle queues are empty
  378. // and the client is under throttle for the type. Queue
  379. // it up directly. This basically short cuts having to
  380. // wait for the timer to fire to put things into the
  381. // output queue
  382. if ((q.Count == 0) && (throttle.UnderLimit()))
  383. {
  384. try
  385. {
  386. Monitor.Enter(this);
  387. throttle.AddBytes(item.Length);
  388. TotalThrottle.AddBytes(item.Length);
  389. SendQueue.Enqueue(item);
  390. }
  391. catch (Exception e)
  392. {
  393. // Probably a serialization exception
  394. m_log.WarnFormat("ThrottleCheck: {0}", e.ToString());
  395. }
  396. finally
  397. {
  398. Monitor.Pulse(this);
  399. Monitor.Exit(this);
  400. }
  401. }
  402. else
  403. {
  404. q.Enqueue(item);
  405. }
  406. }
  407. private static int ScaleThrottle(int value, int curmax, int newmax)
  408. {
  409. return (int)((value / (float)curmax) * newmax);
  410. }
  411. public byte[] GetThrottlesPacked(float multiplier)
  412. {
  413. int singlefloat = 4;
  414. float tResend = ResendThrottle.Throttle*multiplier;
  415. float tLand = LandThrottle.Throttle*multiplier;
  416. float tWind = WindThrottle.Throttle*multiplier;
  417. float tCloud = CloudThrottle.Throttle*multiplier;
  418. float tTask = TaskThrottle.Throttle*multiplier;
  419. float tTexture = TextureThrottle.Throttle*multiplier;
  420. float tAsset = AssetThrottle.Throttle*multiplier;
  421. byte[] throttles = new byte[singlefloat*7];
  422. int i = 0;
  423. Buffer.BlockCopy(BitConverter.GetBytes(tResend), 0, throttles, singlefloat*i, singlefloat);
  424. i++;
  425. Buffer.BlockCopy(BitConverter.GetBytes(tLand), 0, throttles, singlefloat*i, singlefloat);
  426. i++;
  427. Buffer.BlockCopy(BitConverter.GetBytes(tWind), 0, throttles, singlefloat*i, singlefloat);
  428. i++;
  429. Buffer.BlockCopy(BitConverter.GetBytes(tCloud), 0, throttles, singlefloat*i, singlefloat);
  430. i++;
  431. Buffer.BlockCopy(BitConverter.GetBytes(tTask), 0, throttles, singlefloat*i, singlefloat);
  432. i++;
  433. Buffer.BlockCopy(BitConverter.GetBytes(tTexture), 0, throttles, singlefloat*i, singlefloat);
  434. i++;
  435. Buffer.BlockCopy(BitConverter.GetBytes(tAsset), 0, throttles, singlefloat*i, singlefloat);
  436. return throttles;
  437. }
  438. public void SetThrottleFromClient(byte[] throttle)
  439. {
  440. // From mantis http://opensimulator.org/mantis/view.php?id=1374
  441. // it appears that sometimes we are receiving empty throttle byte arrays.
  442. // TODO: Investigate this behaviour
  443. if (throttle.Length == 0)
  444. {
  445. m_log.Warn("[PACKET QUEUE]: SetThrottleFromClient unexpectedly received a throttle byte array containing no elements!");
  446. return;
  447. }
  448. int tResend = -1;
  449. int tLand = -1;
  450. int tWind = -1;
  451. int tCloud = -1;
  452. int tTask = -1;
  453. int tTexture = -1;
  454. int tAsset = -1;
  455. int tall = -1;
  456. int singlefloat = 4;
  457. //Agent Throttle Block contains 7 single floatingpoint values.
  458. int j = 0;
  459. // Some Systems may be big endian...
  460. // it might be smart to do this check more often...
  461. if (!BitConverter.IsLittleEndian)
  462. for (int i = 0; i < 7; i++)
  463. Array.Reverse(throttle, j + i*singlefloat, singlefloat);
  464. // values gotten from OpenMetaverse.org/wiki/Throttle. Thanks MW_
  465. // bytes
  466. // Convert to integer, since.. the full fp space isn't used.
  467. tResend = (int) BitConverter.ToSingle(throttle, j);
  468. j += singlefloat;
  469. tLand = (int) BitConverter.ToSingle(throttle, j);
  470. j += singlefloat;
  471. tWind = (int) BitConverter.ToSingle(throttle, j);
  472. j += singlefloat;
  473. tCloud = (int) BitConverter.ToSingle(throttle, j);
  474. j += singlefloat;
  475. tTask = (int) BitConverter.ToSingle(throttle, j);
  476. j += singlefloat;
  477. tTexture = (int) BitConverter.ToSingle(throttle, j);
  478. j += singlefloat;
  479. tAsset = (int) BitConverter.ToSingle(throttle, j);
  480. tall = tResend + tLand + tWind + tCloud + tTask + tTexture + tAsset;
  481. /*
  482. m_log.Info("[CLIENT]: Client AgentThrottle - Got throttle:resendbits=" + tResend +
  483. " landbits=" + tLand +
  484. " windbits=" + tWind +
  485. " cloudbits=" + tCloud +
  486. " taskbits=" + tTask +
  487. " texturebits=" + tTexture +
  488. " Assetbits=" + tAsset +
  489. " Allbits=" + tall);
  490. */
  491. // Total Sanity
  492. // Make sure that the client sent sane total values.
  493. // If the client didn't send acceptable values....
  494. // Scale the clients values down until they are acceptable.
  495. if (tall <= TotalThrottle.Max)
  496. {
  497. ResendThrottle.Throttle = tResend;
  498. LandThrottle.Throttle = tLand;
  499. WindThrottle.Throttle = tWind;
  500. CloudThrottle.Throttle = tCloud;
  501. TaskThrottle.Throttle = tTask;
  502. TextureThrottle.Throttle = tTexture;
  503. AssetThrottle.Throttle = tAsset;
  504. TotalThrottle.Throttle = tall;
  505. }
  506. // else if (tall < 1)
  507. // {
  508. // // client is stupid, penalize him by minning everything
  509. // ResendThrottle.Throttle = ResendThrottle.Min;
  510. // LandThrottle.Throttle = LandThrottle.Min;
  511. // WindThrottle.Throttle = WindThrottle.Min;
  512. // CloudThrottle.Throttle = CloudThrottle.Min;
  513. // TaskThrottle.Throttle = TaskThrottle.Min;
  514. // TextureThrottle.Throttle = TextureThrottle.Min;
  515. // AssetThrottle.Throttle = AssetThrottle.Min;
  516. // TotalThrottle.Throttle = TotalThrottle.Min;
  517. // }
  518. else
  519. {
  520. // we're over so figure out percentages and use those
  521. ResendThrottle.Throttle = tResend;
  522. LandThrottle.Throttle = ScaleThrottle(tLand, tall, TotalThrottle.Max);
  523. WindThrottle.Throttle = ScaleThrottle(tWind, tall, TotalThrottle.Max);
  524. CloudThrottle.Throttle = ScaleThrottle(tCloud, tall, TotalThrottle.Max);
  525. TaskThrottle.Throttle = ScaleThrottle(tTask, tall, TotalThrottle.Max);
  526. TextureThrottle.Throttle = ScaleThrottle(tTexture, tall, TotalThrottle.Max);
  527. AssetThrottle.Throttle = ScaleThrottle(tAsset, tall, TotalThrottle.Max);
  528. TotalThrottle.Throttle = TotalThrottle.Max;
  529. }
  530. // effectively wiggling the slider causes things reset
  531. // ResetCounters(); // DO NOT reset, better to send less for one period than more
  532. }
  533. // See IPullStatsProvider
  534. public string GetStats()
  535. {
  536. return string.Format("{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}",
  537. SendQueue.Count(),
  538. IncomingPacketQueue.Count,
  539. OutgoingPacketQueue.Count,
  540. ResendOutgoingPacketQueue.Count,
  541. LandOutgoingPacketQueue.Count,
  542. WindOutgoingPacketQueue.Count,
  543. CloudOutgoingPacketQueue.Count,
  544. TaskOutgoingPacketQueue.Count,
  545. TextureOutgoingPacketQueue.Count,
  546. AssetOutgoingPacketQueue.Count);
  547. }
  548. public LLQueItem[] GetQueueArray()
  549. {
  550. return SendQueue.GetQueueArray();
  551. }
  552. }
  553. }