aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ClientStack/PacketQueue.cs252
1 files changed, 252 insertions, 0 deletions
diff --git a/OpenSim/Region/ClientStack/PacketQueue.cs b/OpenSim/Region/ClientStack/PacketQueue.cs
new file mode 100644
index 0000000..b17249b
--- /dev/null
+++ b/OpenSim/Region/ClientStack/PacketQueue.cs
@@ -0,0 +1,252 @@
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*/
28using System;
29using System.Collections.Generic;
30using System.Net;
31using System.Net.Sockets;
32using System.Text;
33using System.Threading;
34using System.Timers;
35using Axiom.Math;
36using libsecondlife;
37using libsecondlife.Packets;
38using OpenSim.Framework;
39using OpenSim.Framework.Communications.Cache;
40using OpenSim.Framework.Console;
41using Timer=System.Timers.Timer;
42
43namespace OpenSim.Region.ClientStack
44{
45 public class PacketQueue
46 {
47 private BlockingQueue<QueItem> SendQueue;
48
49 private Queue<QueItem> IncomingPacketQueue;
50 private Queue<QueItem> OutgoingPacketQueue;
51 private Queue<QueItem> ResendOutgoingPacketQueue;
52 private Queue<QueItem> LandOutgoingPacketQueue;
53 private Queue<QueItem> WindOutgoingPacketQueue;
54 private Queue<QueItem> CloudOutgoingPacketQueue;
55 private Queue<QueItem> TaskOutgoingPacketQueue;
56 private Queue<QueItem> TextureOutgoingPacketQueue;
57 private Queue<QueItem> AssetOutgoingPacketQueue;
58
59 private Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>();
60 private Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>();
61
62 // 1536000
63 private int throttleOutboundMax = 1536000; // Number of bytes allowed to go out per second. (256kbps per client)
64 // TODO: Make this variable. Lower throttle on un-ack. Raise over time?
65 private int bytesSent = 0; // Number of bytes sent this period
66
67 private int throttleOutbound = 162144; // Number of bytes allowed to go out per second. (256kbps per client)
68 // TODO: Make this variable. Lower throttle on un-ack. Raise over time
69
70 // All throttle times and number of bytes are calculated by dividing by this value
71 // This value also determines how many times per throttletimems the timer will run
72 // If throttleimems is 1000 ms, then the timer will fire every 1000/7 milliseconds
73
74 private int throttleTimeDivisor = 7;
75
76 private int throttletimems = 1000;
77
78 // Maximum -per type- throttle
79 private int ResendthrottleMAX = 100000;
80 private int LandthrottleMax = 100000;
81 private int WindthrottleMax = 100000;
82 private int CloudthrottleMax = 100000;
83 private int TaskthrottleMax = 800000;
84 private int AssetthrottleMax = 800000;
85 private int TexturethrottleMax = 800000;
86
87 // Minimum -per type- throttle
88 private int ResendthrottleMin = 5000; // setting resendmin to 0 results in mostly dropped packets
89 private int LandthrottleMin = 1000;
90 private int WindthrottleMin = 1000;
91 private int CloudthrottleMin = 1000;
92 private int TaskthrottleMin = 1000;
93 private int AssetthrottleMin = 1000;
94 private int TexturethrottleMin = 1000;
95
96 // Sim default per-client settings.
97 private int ResendthrottleOutbound = 50000;
98 private int ResendBytesSent = 0;
99 private int LandthrottleOutbound = 100000;
100 private int LandBytesSent = 0;
101 private int WindthrottleOutbound = 10000;
102 private int WindBytesSent = 0;
103 private int CloudthrottleOutbound = 5000;
104 private int CloudBytesSent = 0;
105 private int TaskthrottleOutbound = 100000;
106 private int TaskBytesSent = 0;
107 private int AssetthrottleOutbound = 80000;
108 private int AssetBytesSent = 0;
109 private int TexturethrottleOutbound = 100000;
110 private int TextureBytesSent = 0;
111
112 private Timer throttleTimer;
113
114
115 public PacketQueue()
116 {
117 // While working on this, the BlockingQueue had me fooled for a bit.
118 // The Blocking queue causes the thread to stop until there's something
119 // in it to process. it's an on-purpose threadlock though because
120 // without it, the clientloop will suck up all sim resources.
121
122 SendQueue = new BlockingQueue<QueItem>();
123
124 IncomingPacketQueue = new Queue<QueItem>();
125 OutgoingPacketQueue = new Queue<QueItem>();
126 ResendOutgoingPacketQueue = new Queue<QueItem>();
127 LandOutgoingPacketQueue = new Queue<QueItem>();
128 WindOutgoingPacketQueue = new Queue<QueItem>();
129 CloudOutgoingPacketQueue = new Queue<QueItem>();
130 TaskOutgoingPacketQueue = new Queue<QueItem>();
131 TextureOutgoingPacketQueue = new Queue<QueItem>();
132 AssetOutgoingPacketQueue = new Queue<QueItem>();
133
134 // TIMERS needed for this
135 ResetCounters();
136
137 throttleTimer = new Timer((int)(throttletimems/throttleTimeDivisor));
138 throttleTimer.Elapsed += new ElapsedEventHandler(throttleTimer_Elapsed);
139 throttleTimer.Start();
140 }
141
142 private void ResetCounters()
143 {
144 bytesSent = 0;
145 ResendBytesSent = 0;
146 LandBytesSent = 0;
147 WindBytesSent = 0;
148 CloudBytesSent = 0;
149 TaskBytesSent = 0;
150 AssetBytesSent = 0;
151 TextureBytesSent = 0;
152 }
153
154 private bool PacketsWaiting()
155 {
156 return (ResendOutgoingPacketQueue.Count > 0 ||
157 LandOutgoingPacketQueue.Count > 0 ||
158 WindOutgoingPacketQueue.Count > 0 ||
159 CloudOutgoingPacketQueue.Count > 0 ||
160 TaskOutgoingPacketQueue.Count > 0 ||
161 AssetOutgoingPacketQueue.Count > 0 ||
162 TextureOutgoingPacketQueue.Count > 0);
163 }
164
165
166 private void throttleTimer_Elapsed(object sender, ElapsedEventArgs e)
167 {
168 ResetCounters();
169
170 // I was considering this.. Will an event fire if the thread it's on is blocked?
171
172 // Then I figured out.. it doesn't really matter.. because this thread won't be blocked for long
173 // The General overhead of the UDP protocol gets sent to the queue un-throttled by this
174 // so This'll pick up about around the right time.
175
176 int MaxThrottleLoops = 4550; // 50*7 packets can be dequeued at once.
177 int throttleLoops = 0;
178
179 // We're going to dequeue all of the saved up packets until
180 // we've hit the throttle limit or there's no more packets to send
181 while ((bytesSent <= (int)(throttleOutbound/throttleTimeDivisor)) &&
182 PacketsWaiting() && (throttleLoops <= MaxThrottleLoops))
183 {
184 throttleLoops++;
185 //Now comes the fun part.. we dump all our elements into PacketQueue that we've saved up.
186 if (ResendBytesSent <= ((int)(ResendthrottleOutbound/throttleTimeDivisor)) && ResendOutgoingPacketQueue.Count > 0)
187 {
188 QueItem qpack = ResendOutgoingPacketQueue.Dequeue();
189
190 SendQueue.Enqueue(qpack);
191 bytesSent += qpack.Packet.ToBytes().Length;
192 ResendBytesSent += qpack.Packet.ToBytes().Length;
193 }
194 if (LandBytesSent <= ((int)(LandthrottleOutbound/throttleTimeDivisor)) && LandOutgoingPacketQueue.Count > 0)
195 {
196 QueItem qpack = LandOutgoingPacketQueue.Dequeue();
197
198 SendQueue.Enqueue(qpack);
199 bytesSent += qpack.Packet.ToBytes().Length;
200 LandBytesSent += qpack.Packet.ToBytes().Length;
201 }
202 if (WindBytesSent <= ((int)(WindthrottleOutbound/throttleTimeDivisor)) && WindOutgoingPacketQueue.Count > 0)
203 {
204 QueItem qpack = WindOutgoingPacketQueue.Dequeue();
205
206 SendQueue.Enqueue(qpack);
207 bytesSent += qpack.Packet.ToBytes().Length;
208 WindBytesSent += qpack.Packet.ToBytes().Length;
209 }
210 if (CloudBytesSent <= ((int)(CloudthrottleOutbound/throttleTimeDivisor)) && CloudOutgoingPacketQueue.Count > 0)
211 {
212 QueItem qpack = CloudOutgoingPacketQueue.Dequeue();
213
214 SendQueue.Enqueue(qpack);
215 bytesSent += qpack.Packet.ToBytes().Length;
216 CloudBytesSent += qpack.Packet.ToBytes().Length;
217 }
218 if (TaskBytesSent <= ((int)(TaskthrottleOutbound/throttleTimeDivisor)) && TaskOutgoingPacketQueue.Count > 0)
219 {
220 QueItem qpack = TaskOutgoingPacketQueue.Dequeue();
221
222 SendQueue.Enqueue(qpack);
223 bytesSent += qpack.Packet.ToBytes().Length;
224 TaskBytesSent += qpack.Packet.ToBytes().Length;
225 }
226 if (TextureBytesSent <= ((int)(TexturethrottleOutbound/throttleTimeDivisor)) && TextureOutgoingPacketQueue.Count > 0)
227 {
228 QueItem qpack = TextureOutgoingPacketQueue.Dequeue();
229
230 SendQueue.Enqueue(qpack);
231 bytesSent += qpack.Packet.ToBytes().Length;
232 TextureBytesSent += qpack.Packet.ToBytes().Length;
233 }
234 if (AssetBytesSent <= ((int)(AssetthrottleOutbound/throttleTimeDivisor)) && AssetOutgoingPacketQueue.Count > 0)
235 {
236 QueItem qpack = AssetOutgoingPacketQueue.Dequeue();
237
238 SendQueue.Enqueue(qpack);
239 bytesSent += qpack.Packet.ToBytes().Length;
240 AssetBytesSent += qpack.Packet.ToBytes().Length;
241 }
242
243 }
244
245 }
246
247
248 }
249
250
251
252} \ No newline at end of file