LLPacketQueue.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  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. lock (this)
  230. {
  231. ResendOutgoingPacketQueue.Clear();
  232. LandOutgoingPacketQueue.Clear();
  233. WindOutgoingPacketQueue.Clear();
  234. CloudOutgoingPacketQueue.Clear();
  235. TaskOutgoingPacketQueue.Clear();
  236. TaskLowpriorityPacketQueue.Clear();
  237. TextureOutgoingPacketQueue.Clear();
  238. AssetOutgoingPacketQueue.Clear();
  239. SendQueue.Clear();
  240. }
  241. }
  242. public void Close()
  243. {
  244. Flush();
  245. WipeClean(); // I'm sure there's a dirty joke in here somewhere. -AFrisby
  246. m_enabled = false;
  247. throttleTimer.Stop();
  248. if (StatsManager.SimExtraStats != null)
  249. {
  250. StatsManager.SimExtraStats.DeregisterPacketQueueStatsProvider(m_agentId);
  251. }
  252. }
  253. private void ResetCounters()
  254. {
  255. ResendThrottle.Reset();
  256. LandThrottle.Reset();
  257. WindThrottle.Reset();
  258. CloudThrottle.Reset();
  259. TaskThrottle.Reset();
  260. AssetThrottle.Reset();
  261. TextureThrottle.Reset();
  262. TotalThrottle.Reset();
  263. }
  264. private bool PacketsWaiting()
  265. {
  266. return (ResendOutgoingPacketQueue.Count > 0 ||
  267. LandOutgoingPacketQueue.Count > 0 ||
  268. WindOutgoingPacketQueue.Count > 0 ||
  269. CloudOutgoingPacketQueue.Count > 0 ||
  270. TaskOutgoingPacketQueue.Count > 0 ||
  271. TaskLowpriorityPacketQueue.Count > 0 ||
  272. AssetOutgoingPacketQueue.Count > 0 ||
  273. TextureOutgoingPacketQueue.Count > 0);
  274. }
  275. public void ProcessThrottle()
  276. {
  277. // I was considering this.. Will an event fire if the thread it's on is blocked?
  278. // Then I figured out.. it doesn't really matter.. because this thread won't be blocked for long
  279. // The General overhead of the UDP protocol gets sent to the queue un-throttled by this
  280. // so This'll pick up about around the right time.
  281. int MaxThrottleLoops = 4550; // 50*7 packets can be dequeued at once.
  282. int throttleLoops = 0;
  283. // We're going to dequeue all of the saved up packets until
  284. // we've hit the throttle limit or there's no more packets to send
  285. lock (this)
  286. {
  287. // this variable will be true if there was work done in the last execution of the
  288. // loop, since each pass through the loop checks the queue length, we no longer
  289. // need the check on entering the loop
  290. bool qchanged = true;
  291. ResetCounters();
  292. // m_log.Info("[THROTTLE]: Entering Throttle");
  293. while (TotalThrottle.UnderLimit() && qchanged && throttleLoops <= MaxThrottleLoops)
  294. {
  295. qchanged = false; // We will break out of the loop if no work was accomplished
  296. throttleLoops++;
  297. //Now comes the fun part.. we dump all our elements into m_packetQueue that we've saved up.
  298. if ((ResendOutgoingPacketQueue.Count > 0) && ResendThrottle.UnderLimit())
  299. {
  300. LLQueItem qpack = ResendOutgoingPacketQueue.Dequeue();
  301. SendQueue.Enqueue(qpack);
  302. TotalThrottle.AddBytes(qpack.Length);
  303. ResendThrottle.AddBytes(qpack.Length);
  304. qchanged = true;
  305. }
  306. if ((LandOutgoingPacketQueue.Count > 0) && LandThrottle.UnderLimit())
  307. {
  308. LLQueItem qpack = LandOutgoingPacketQueue.Dequeue();
  309. SendQueue.Enqueue(qpack);
  310. TotalThrottle.AddBytes(qpack.Length);
  311. LandThrottle.AddBytes(qpack.Length);
  312. qchanged = true;
  313. }
  314. if ((WindOutgoingPacketQueue.Count > 0) && WindThrottle.UnderLimit())
  315. {
  316. LLQueItem qpack = WindOutgoingPacketQueue.Dequeue();
  317. SendQueue.Enqueue(qpack);
  318. TotalThrottle.AddBytes(qpack.Length);
  319. WindThrottle.AddBytes(qpack.Length);
  320. qchanged = true;
  321. }
  322. if ((CloudOutgoingPacketQueue.Count > 0) && CloudThrottle.UnderLimit())
  323. {
  324. LLQueItem qpack = CloudOutgoingPacketQueue.Dequeue();
  325. SendQueue.Enqueue(qpack);
  326. TotalThrottle.AddBytes(qpack.Length);
  327. CloudThrottle.AddBytes(qpack.Length);
  328. qchanged = true;
  329. }
  330. if ((TaskOutgoingPacketQueue.Count > 0 || TaskLowpriorityPacketQueue.Count > 0) && TaskThrottle.UnderLimit())
  331. {
  332. LLQueItem qpack;
  333. if (TaskOutgoingPacketQueue.Count > 0)
  334. {
  335. qpack = TaskOutgoingPacketQueue.Dequeue();
  336. SendQueue.PriorityEnqueue(qpack);
  337. }
  338. else
  339. {
  340. qpack = TaskLowpriorityPacketQueue.Dequeue();
  341. SendQueue.Enqueue(qpack);
  342. }
  343. TotalThrottle.AddBytes(qpack.Length);
  344. TaskThrottle.AddBytes(qpack.Length);
  345. qchanged = true;
  346. }
  347. if ((TextureOutgoingPacketQueue.Count > 0) && TextureThrottle.UnderLimit())
  348. {
  349. LLQueItem qpack = TextureOutgoingPacketQueue.Dequeue();
  350. SendQueue.Enqueue(qpack);
  351. TotalThrottle.AddBytes(qpack.Length);
  352. TextureThrottle.AddBytes(qpack.Length);
  353. qchanged = true;
  354. }
  355. if ((AssetOutgoingPacketQueue.Count > 0) && AssetThrottle.UnderLimit())
  356. {
  357. LLQueItem qpack = AssetOutgoingPacketQueue.Dequeue();
  358. SendQueue.Enqueue(qpack);
  359. TotalThrottle.AddBytes(qpack.Length);
  360. AssetThrottle.AddBytes(qpack.Length);
  361. qchanged = true;
  362. }
  363. }
  364. // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets");
  365. }
  366. }
  367. private void ThrottleTimerElapsed(object sender, ElapsedEventArgs e)
  368. {
  369. // just to change the signature, and that ProcessThrottle
  370. // will be used elsewhere possibly
  371. ProcessThrottle();
  372. }
  373. private void ThrottleCheck(ref LLPacketThrottle throttle, ref Queue<LLQueItem> q, LLQueItem item)
  374. {
  375. // The idea.. is if the packet throttle queues are empty
  376. // and the client is under throttle for the type. Queue
  377. // it up directly. This basically short cuts having to
  378. // wait for the timer to fire to put things into the
  379. // output queue
  380. if ((q.Count == 0) && (throttle.UnderLimit()))
  381. {
  382. try
  383. {
  384. Monitor.Enter(this);
  385. throttle.AddBytes(item.Length);
  386. TotalThrottle.AddBytes(item.Length);
  387. SendQueue.Enqueue(item);
  388. }
  389. catch (Exception e)
  390. {
  391. // Probably a serialization exception
  392. m_log.WarnFormat("ThrottleCheck: {0}", e.ToString());
  393. }
  394. finally
  395. {
  396. Monitor.Pulse(this);
  397. Monitor.Exit(this);
  398. }
  399. }
  400. else
  401. {
  402. q.Enqueue(item);
  403. }
  404. }
  405. private static int ScaleThrottle(int value, int curmax, int newmax)
  406. {
  407. return (int)((value / (float)curmax) * newmax);
  408. }
  409. public byte[] GetThrottlesPacked(float multiplier)
  410. {
  411. int singlefloat = 4;
  412. float tResend = ResendThrottle.Throttle*multiplier;
  413. float tLand = LandThrottle.Throttle*multiplier;
  414. float tWind = WindThrottle.Throttle*multiplier;
  415. float tCloud = CloudThrottle.Throttle*multiplier;
  416. float tTask = TaskThrottle.Throttle*multiplier;
  417. float tTexture = TextureThrottle.Throttle*multiplier;
  418. float tAsset = AssetThrottle.Throttle*multiplier;
  419. byte[] throttles = new byte[singlefloat*7];
  420. int i = 0;
  421. Buffer.BlockCopy(BitConverter.GetBytes(tResend), 0, throttles, singlefloat*i, singlefloat);
  422. i++;
  423. Buffer.BlockCopy(BitConverter.GetBytes(tLand), 0, throttles, singlefloat*i, singlefloat);
  424. i++;
  425. Buffer.BlockCopy(BitConverter.GetBytes(tWind), 0, throttles, singlefloat*i, singlefloat);
  426. i++;
  427. Buffer.BlockCopy(BitConverter.GetBytes(tCloud), 0, throttles, singlefloat*i, singlefloat);
  428. i++;
  429. Buffer.BlockCopy(BitConverter.GetBytes(tTask), 0, throttles, singlefloat*i, singlefloat);
  430. i++;
  431. Buffer.BlockCopy(BitConverter.GetBytes(tTexture), 0, throttles, singlefloat*i, singlefloat);
  432. i++;
  433. Buffer.BlockCopy(BitConverter.GetBytes(tAsset), 0, throttles, singlefloat*i, singlefloat);
  434. return throttles;
  435. }
  436. public void SetThrottleFromClient(byte[] throttle)
  437. {
  438. // From mantis http://opensimulator.org/mantis/view.php?id=1374
  439. // it appears that sometimes we are receiving empty throttle byte arrays.
  440. // TODO: Investigate this behaviour
  441. if (throttle.Length == 0)
  442. {
  443. m_log.Warn("[PACKET QUEUE]: SetThrottleFromClient unexpectedly received a throttle byte array containing no elements!");
  444. return;
  445. }
  446. int tResend = -1;
  447. int tLand = -1;
  448. int tWind = -1;
  449. int tCloud = -1;
  450. int tTask = -1;
  451. int tTexture = -1;
  452. int tAsset = -1;
  453. int tall = -1;
  454. int singlefloat = 4;
  455. //Agent Throttle Block contains 7 single floatingpoint values.
  456. int j = 0;
  457. // Some Systems may be big endian...
  458. // it might be smart to do this check more often...
  459. if (!BitConverter.IsLittleEndian)
  460. for (int i = 0; i < 7; i++)
  461. Array.Reverse(throttle, j + i*singlefloat, singlefloat);
  462. // values gotten from OpenMetaverse.org/wiki/Throttle. Thanks MW_
  463. // bytes
  464. // Convert to integer, since.. the full fp space isn't used.
  465. tResend = (int) BitConverter.ToSingle(throttle, j);
  466. j += singlefloat;
  467. tLand = (int) BitConverter.ToSingle(throttle, j);
  468. j += singlefloat;
  469. tWind = (int) BitConverter.ToSingle(throttle, j);
  470. j += singlefloat;
  471. tCloud = (int) BitConverter.ToSingle(throttle, j);
  472. j += singlefloat;
  473. tTask = (int) BitConverter.ToSingle(throttle, j);
  474. j += singlefloat;
  475. tTexture = (int) BitConverter.ToSingle(throttle, j);
  476. j += singlefloat;
  477. tAsset = (int) BitConverter.ToSingle(throttle, j);
  478. tall = tResend + tLand + tWind + tCloud + tTask + tTexture + tAsset;
  479. /*
  480. m_log.Info("[CLIENT]: Client AgentThrottle - Got throttle:resendbits=" + tResend +
  481. " landbits=" + tLand +
  482. " windbits=" + tWind +
  483. " cloudbits=" + tCloud +
  484. " taskbits=" + tTask +
  485. " texturebits=" + tTexture +
  486. " Assetbits=" + tAsset +
  487. " Allbits=" + tall);
  488. */
  489. // Total Sanity
  490. // Make sure that the client sent sane total values.
  491. // If the client didn't send acceptable values....
  492. // Scale the clients values down until they are acceptable.
  493. if (tall <= TotalThrottle.Max)
  494. {
  495. ResendThrottle.Throttle = tResend;
  496. LandThrottle.Throttle = tLand;
  497. WindThrottle.Throttle = tWind;
  498. CloudThrottle.Throttle = tCloud;
  499. TaskThrottle.Throttle = tTask;
  500. TextureThrottle.Throttle = tTexture;
  501. AssetThrottle.Throttle = tAsset;
  502. TotalThrottle.Throttle = tall;
  503. }
  504. // else if (tall < 1)
  505. // {
  506. // // client is stupid, penalize him by minning everything
  507. // ResendThrottle.Throttle = ResendThrottle.Min;
  508. // LandThrottle.Throttle = LandThrottle.Min;
  509. // WindThrottle.Throttle = WindThrottle.Min;
  510. // CloudThrottle.Throttle = CloudThrottle.Min;
  511. // TaskThrottle.Throttle = TaskThrottle.Min;
  512. // TextureThrottle.Throttle = TextureThrottle.Min;
  513. // AssetThrottle.Throttle = AssetThrottle.Min;
  514. // TotalThrottle.Throttle = TotalThrottle.Min;
  515. // }
  516. else
  517. {
  518. // we're over so figure out percentages and use those
  519. ResendThrottle.Throttle = tResend;
  520. LandThrottle.Throttle = ScaleThrottle(tLand, tall, TotalThrottle.Max);
  521. WindThrottle.Throttle = ScaleThrottle(tWind, tall, TotalThrottle.Max);
  522. CloudThrottle.Throttle = ScaleThrottle(tCloud, tall, TotalThrottle.Max);
  523. TaskThrottle.Throttle = ScaleThrottle(tTask, tall, TotalThrottle.Max);
  524. TextureThrottle.Throttle = ScaleThrottle(tTexture, tall, TotalThrottle.Max);
  525. AssetThrottle.Throttle = ScaleThrottle(tAsset, tall, TotalThrottle.Max);
  526. TotalThrottle.Throttle = TotalThrottle.Max;
  527. }
  528. // effectively wiggling the slider causes things reset
  529. // ResetCounters(); // DO NOT reset, better to send less for one period than more
  530. }
  531. // See IPullStatsProvider
  532. public string GetStats()
  533. {
  534. return string.Format("{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}",
  535. SendQueue.Count(),
  536. IncomingPacketQueue.Count,
  537. OutgoingPacketQueue.Count,
  538. ResendOutgoingPacketQueue.Count,
  539. LandOutgoingPacketQueue.Count,
  540. WindOutgoingPacketQueue.Count,
  541. CloudOutgoingPacketQueue.Count,
  542. TaskOutgoingPacketQueue.Count,
  543. TextureOutgoingPacketQueue.Count,
  544. AssetOutgoingPacketQueue.Count);
  545. }
  546. public LLQueItem[] GetQueueArray()
  547. {
  548. return SendQueue.GetQueueArray();
  549. }
  550. }
  551. }