PacketPool.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  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 OpenMetaverse;
  31. using OpenMetaverse.Packets;
  32. using log4net;
  33. namespace OpenSim.Framework
  34. {
  35. public sealed class PacketPool
  36. {
  37. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  38. private static readonly PacketPool instance = new PacketPool();
  39. private bool packetPoolEnabled = true;
  40. private bool dataBlockPoolEnabled = true;
  41. private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>();
  42. private static Dictionary<Type, Stack<Object>> DataBlocks =
  43. new Dictionary<Type, Stack<Object>>();
  44. static PacketPool()
  45. {
  46. }
  47. public static PacketPool Instance
  48. {
  49. get { return instance; }
  50. }
  51. public bool RecyclePackets
  52. {
  53. set { packetPoolEnabled = value; }
  54. get { return packetPoolEnabled; }
  55. }
  56. public bool RecycleDataBlocks
  57. {
  58. set { dataBlockPoolEnabled = value; }
  59. get { return dataBlockPoolEnabled; }
  60. }
  61. public Packet GetPacket(PacketType type)
  62. {
  63. Packet packet;
  64. if (!packetPoolEnabled)
  65. return Packet.BuildPacket(type);
  66. lock (pool)
  67. {
  68. if (!pool.ContainsKey(type) || pool[type] == null || (pool[type]).Count == 0)
  69. {
  70. // Creating a new packet if we cannot reuse an old package
  71. packet = Packet.BuildPacket(type);
  72. }
  73. else
  74. {
  75. // Recycle old packages
  76. packet = (pool[type]).Pop();
  77. }
  78. }
  79. return packet;
  80. }
  81. // private byte[] decoded_header = new byte[10];
  82. private static PacketType GetType(byte[] bytes)
  83. {
  84. byte[] decoded_header = new byte[10 + 8];
  85. ushort id;
  86. PacketFrequency freq;
  87. if ((bytes[0] & Helpers.MSG_ZEROCODED) != 0)
  88. {
  89. Helpers.ZeroDecode(bytes, 16, decoded_header);
  90. }
  91. else
  92. {
  93. Buffer.BlockCopy(bytes, 0, decoded_header, 0, 10);
  94. }
  95. if (decoded_header[6] == 0xFF)
  96. {
  97. if (decoded_header[7] == 0xFF)
  98. {
  99. id = (ushort) ((decoded_header[8] << 8) + decoded_header[9]);
  100. freq = PacketFrequency.Low;
  101. }
  102. else
  103. {
  104. id = decoded_header[7];
  105. freq = PacketFrequency.Medium;
  106. }
  107. }
  108. else
  109. {
  110. id = decoded_header[6];
  111. freq = PacketFrequency.High;
  112. }
  113. return Packet.GetType(id, freq);
  114. }
  115. public Packet GetPacket(byte[] bytes, ref int packetEnd, byte[] zeroBuffer)
  116. {
  117. PacketType type = GetType(bytes);
  118. Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
  119. int i = 0;
  120. Packet packet = GetPacket(type);
  121. if (packet == null)
  122. m_log.WarnFormat("[PACKETPOOL]: Failed to get packet of type {0}", type);
  123. else
  124. packet.FromBytes(bytes, ref i, ref packetEnd, zeroBuffer);
  125. return packet;
  126. }
  127. /// <summary>
  128. /// Return a packet to the packet pool
  129. /// </summary>
  130. /// <param name="packet"></param>
  131. public void ReturnPacket(Packet packet)
  132. {
  133. if (dataBlockPoolEnabled)
  134. {
  135. switch (packet.Type)
  136. {
  137. case PacketType.ObjectUpdate:
  138. ObjectUpdatePacket oup = (ObjectUpdatePacket)packet;
  139. foreach (ObjectUpdatePacket.ObjectDataBlock oupod in oup.ObjectData)
  140. ReturnDataBlock<ObjectUpdatePacket.ObjectDataBlock>(oupod);
  141. oup.ObjectData = null;
  142. break;
  143. case PacketType.ImprovedTerseObjectUpdate:
  144. ImprovedTerseObjectUpdatePacket itoup = (ImprovedTerseObjectUpdatePacket)packet;
  145. foreach (ImprovedTerseObjectUpdatePacket.ObjectDataBlock itoupod in itoup.ObjectData)
  146. ReturnDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(itoupod);
  147. itoup.ObjectData = null;
  148. break;
  149. }
  150. }
  151. if (packetPoolEnabled)
  152. {
  153. switch (packet.Type)
  154. {
  155. // List pooling packets here
  156. case PacketType.PacketAck:
  157. case PacketType.ObjectUpdate:
  158. case PacketType.ImprovedTerseObjectUpdate:
  159. lock (pool)
  160. {
  161. PacketType type = packet.Type;
  162. if (!pool.ContainsKey(type))
  163. {
  164. pool[type] = new Stack<Packet>();
  165. }
  166. if ((pool[type]).Count < 50)
  167. {
  168. (pool[type]).Push(packet);
  169. }
  170. }
  171. break;
  172. // Other packets wont pool
  173. default:
  174. return;
  175. }
  176. }
  177. }
  178. public static T GetDataBlock<T>() where T: new()
  179. {
  180. lock (DataBlocks)
  181. {
  182. Stack<Object> s;
  183. if (DataBlocks.TryGetValue(typeof(T), out s))
  184. {
  185. if (s.Count > 0)
  186. return (T)s.Pop();
  187. }
  188. else
  189. {
  190. DataBlocks[typeof(T)] = new Stack<Object>();
  191. }
  192. return new T();
  193. }
  194. }
  195. public static void ReturnDataBlock<T>(T block) where T: new()
  196. {
  197. if (block == null)
  198. return;
  199. lock (DataBlocks)
  200. {
  201. if (!DataBlocks.ContainsKey(typeof(T)))
  202. DataBlocks[typeof(T)] = new Stack<Object>();
  203. if (DataBlocks[typeof(T)].Count < 50)
  204. DataBlocks[typeof(T)].Push(block);
  205. }
  206. }
  207. }
  208. }