aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs306
1 files changed, 306 insertions, 0 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
new file mode 100644
index 0000000..1fdc410
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
@@ -0,0 +1,306 @@
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
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using OpenMetaverse;
32using OpenMetaverse.Packets;
33using log4net;
34using OpenSim.Framework.Monitoring;
35
36namespace OpenSim.Region.ClientStack.LindenUDP
37{
38 public sealed class PacketPool
39 {
40 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
41
42 private static readonly PacketPool instance = new PacketPool();
43
44 /// <summary>
45 /// Pool of packets available for reuse.
46 /// </summary>
47 private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>();
48
49 private static Dictionary<Type, Stack<Object>> DataBlocks = new Dictionary<Type, Stack<Object>>();
50
51 public static PacketPool Instance
52 {
53 get { return instance; }
54 }
55
56 public bool RecyclePackets { get; set; }
57
58 public bool RecycleDataBlocks { get; set; }
59
60 /// <summary>
61 /// The number of packets pooled
62 /// </summary>
63 public int PacketsPooled
64 {
65 get
66 {
67 lock (pool)
68 return pool.Count;
69 }
70 }
71
72 /// <summary>
73 /// The number of blocks pooled.
74 /// </summary>
75 public int BlocksPooled
76 {
77 get
78 {
79 lock (DataBlocks)
80 return DataBlocks.Count;
81 }
82 }
83
84 /// <summary>
85 /// Number of packets requested.
86 /// </summary>
87 public long PacketsRequested { get; private set; }
88
89 /// <summary>
90 /// Number of packets reused.
91 /// </summary>
92 public long PacketsReused { get; private set; }
93
94 /// <summary>
95 /// Number of packet blocks requested.
96 /// </summary>
97 public long BlocksRequested { get; private set; }
98
99 /// <summary>
100 /// Number of packet blocks reused.
101 /// </summary>
102 public long BlocksReused { get; private set; }
103
104 private PacketPool()
105 {
106 // defaults
107 RecyclePackets = true;
108 RecycleDataBlocks = true;
109 }
110
111 /// <summary>
112 /// Gets a packet of the given type.
113 /// </summary>
114 /// <param name='type'></param>
115 /// <returns>Guaranteed to always return a packet, whether from the pool or newly constructed.</returns>
116 public Packet GetPacket(PacketType type)
117 {
118 PacketsRequested++;
119
120 Packet packet;
121
122 if (!RecyclePackets)
123 return Packet.BuildPacket(type);
124
125 lock (pool)
126 {
127 if (!pool.ContainsKey(type) || pool[type] == null || (pool[type]).Count == 0)
128 {
129// m_log.DebugFormat("[PACKETPOOL]: Building {0} packet", type);
130
131 // Creating a new packet if we cannot reuse an old package
132 packet = Packet.BuildPacket(type);
133 }
134 else
135 {
136// m_log.DebugFormat("[PACKETPOOL]: Pulling {0} packet", type);
137
138 // Recycle old packages
139 PacketsReused++;
140
141 packet = pool[type].Pop();
142 }
143 }
144
145 return packet;
146 }
147
148 // private byte[] decoded_header = new byte[10];
149 private static PacketType GetType(byte[] bytes)
150 {
151 byte[] decoded_header = new byte[10 + 8];
152 ushort id;
153 PacketFrequency freq;
154
155 if ((bytes[0] & Helpers.MSG_ZEROCODED) != 0)
156 {
157 Helpers.ZeroDecode(bytes, 16, decoded_header);
158 }
159 else
160 {
161 Buffer.BlockCopy(bytes, 0, decoded_header, 0, 10);
162 }
163
164 if (decoded_header[6] == 0xFF)
165 {
166 if (decoded_header[7] == 0xFF)
167 {
168 id = (ushort) ((decoded_header[8] << 8) + decoded_header[9]);
169 freq = PacketFrequency.Low;
170 }
171 else
172 {
173 id = decoded_header[7];
174 freq = PacketFrequency.Medium;
175 }
176 }
177 else
178 {
179 id = decoded_header[6];
180 freq = PacketFrequency.High;
181 }
182
183 return Packet.GetType(id, freq);
184 }
185
186 public Packet GetPacket(byte[] bytes, ref int packetEnd, byte[] zeroBuffer)
187 {
188 PacketType type = GetType(bytes);
189
190// Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
191
192 int i = 0;
193 Packet packet = GetPacket(type);
194 if (packet == null)
195 m_log.WarnFormat("[PACKETPOOL]: Failed to get packet of type {0}", type);
196 else
197 packet.FromBytes(bytes, ref i, ref packetEnd, zeroBuffer);
198
199 return packet;
200 }
201
202 /// <summary>
203 /// Return a packet to the packet pool
204 /// </summary>
205 /// <param name="packet"></param>
206 public void ReturnPacket(Packet packet)
207 {
208 if (RecycleDataBlocks)
209 {
210 switch (packet.Type)
211 {
212 case PacketType.ObjectUpdate:
213 ObjectUpdatePacket oup = (ObjectUpdatePacket)packet;
214
215 foreach (ObjectUpdatePacket.ObjectDataBlock oupod in oup.ObjectData)
216 ReturnDataBlock<ObjectUpdatePacket.ObjectDataBlock>(oupod);
217
218 oup.ObjectData = null;
219 break;
220
221 case PacketType.ImprovedTerseObjectUpdate:
222 ImprovedTerseObjectUpdatePacket itoup = (ImprovedTerseObjectUpdatePacket)packet;
223
224 foreach (ImprovedTerseObjectUpdatePacket.ObjectDataBlock itoupod in itoup.ObjectData)
225 ReturnDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(itoupod);
226
227 itoup.ObjectData = null;
228 break;
229 }
230 }
231
232 if (RecyclePackets)
233 {
234 switch (packet.Type)
235 {
236 // List pooling packets here
237 case PacketType.AgentUpdate:
238 case PacketType.PacketAck:
239 case PacketType.ObjectUpdate:
240 case PacketType.ImprovedTerseObjectUpdate:
241 lock (pool)
242 {
243 PacketType type = packet.Type;
244
245 if (!pool.ContainsKey(type))
246 {
247 pool[type] = new Stack<Packet>();
248 }
249
250 if ((pool[type]).Count < 50)
251 {
252// m_log.DebugFormat("[PACKETPOOL]: Pushing {0} packet", type);
253
254 pool[type].Push(packet);
255 }
256 }
257 break;
258
259 // Other packets wont pool
260 default:
261 return;
262 }
263 }
264 }
265
266 public T GetDataBlock<T>() where T: new()
267 {
268 lock (DataBlocks)
269 {
270 BlocksRequested++;
271
272 Stack<Object> s;
273
274 if (DataBlocks.TryGetValue(typeof(T), out s))
275 {
276 if (s.Count > 0)
277 {
278 BlocksReused++;
279 return (T)s.Pop();
280 }
281 }
282 else
283 {
284 DataBlocks[typeof(T)] = new Stack<Object>();
285 }
286
287 return new T();
288 }
289 }
290
291 public void ReturnDataBlock<T>(T block) where T: new()
292 {
293 if (block == null)
294 return;
295
296 lock (DataBlocks)
297 {
298 if (!DataBlocks.ContainsKey(typeof(T)))
299 DataBlocks[typeof(T)] = new Stack<Object>();
300
301 if (DataBlocks[typeof(T)].Count < 50)
302 DataBlocks[typeof(T)].Push(block);
303 }
304 }
305 }
306} \ No newline at end of file