LLPacketQueue.cs 29 KB

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