diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/PacketQueue.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/PacketQueue.cs | 252 |
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 | */ | ||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Net; | ||
31 | using System.Net.Sockets; | ||
32 | using System.Text; | ||
33 | using System.Threading; | ||
34 | using System.Timers; | ||
35 | using Axiom.Math; | ||
36 | using libsecondlife; | ||
37 | using libsecondlife.Packets; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Framework.Communications.Cache; | ||
40 | using OpenSim.Framework.Console; | ||
41 | using Timer=System.Timers.Timer; | ||
42 | |||
43 | namespace 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 | ||