diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP')
15 files changed, 1894 insertions, 894 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacketAsyncHandlingEngine.cs b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacketAsyncHandlingEngine.cs new file mode 100644 index 0000000..6f40b24 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacketAsyncHandlingEngine.cs | |||
@@ -0,0 +1,328 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Concurrent; | ||
30 | using System.Reflection; | ||
31 | using System.Threading; | ||
32 | using log4net; | ||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Framework.Monitoring; | ||
35 | using OpenSim.Region.Framework.Scenes; | ||
36 | |||
37 | namespace OpenSim.Region.ClientStack.LindenUDP | ||
38 | { | ||
39 | public class Job | ||
40 | { | ||
41 | public string Name; | ||
42 | public WaitCallback Callback; | ||
43 | public object O; | ||
44 | |||
45 | public Job(string name, WaitCallback callback, object o) | ||
46 | { | ||
47 | Name = name; | ||
48 | Callback = callback; | ||
49 | O = o; | ||
50 | } | ||
51 | } | ||
52 | |||
53 | // TODO: These kinds of classes MUST be generalized with JobEngine, etc. | ||
54 | public class IncomingPacketAsyncHandlingEngine | ||
55 | { | ||
56 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
57 | |||
58 | public int LogLevel { get; set; } | ||
59 | |||
60 | public bool IsRunning { get; private set; } | ||
61 | |||
62 | /// <summary> | ||
63 | /// The timeout in milliseconds to wait for at least one event to be written when the recorder is stopping. | ||
64 | /// </summary> | ||
65 | public int RequestProcessTimeoutOnStop { get; set; } | ||
66 | |||
67 | /// <summary> | ||
68 | /// Controls whether we need to warn in the log about exceeding the max queue size. | ||
69 | /// </summary> | ||
70 | /// <remarks> | ||
71 | /// This is flipped to false once queue max has been exceeded and back to true when it falls below max, in | ||
72 | /// order to avoid spamming the log with lots of warnings. | ||
73 | /// </remarks> | ||
74 | private bool m_warnOverMaxQueue = true; | ||
75 | |||
76 | private BlockingCollection<Job> m_requestQueue; | ||
77 | |||
78 | private CancellationTokenSource m_cancelSource = new CancellationTokenSource(); | ||
79 | |||
80 | private LLUDPServer m_udpServer; | ||
81 | |||
82 | private Stat m_requestsWaitingStat; | ||
83 | |||
84 | private Job m_currentJob; | ||
85 | |||
86 | /// <summary> | ||
87 | /// Used to signal that we are ready to complete stop. | ||
88 | /// </summary> | ||
89 | private ManualResetEvent m_finishedProcessingAfterStop = new ManualResetEvent(false); | ||
90 | |||
91 | public IncomingPacketAsyncHandlingEngine(LLUDPServer server) | ||
92 | { | ||
93 | //LogLevel = 1; | ||
94 | m_udpServer = server; | ||
95 | RequestProcessTimeoutOnStop = 5000; | ||
96 | |||
97 | // MainConsole.Instance.Commands.AddCommand( | ||
98 | // "Debug", | ||
99 | // false, | ||
100 | // "debug jobengine", | ||
101 | // "debug jobengine <start|stop|status>", | ||
102 | // "Start, stop or get status of the job engine.", | ||
103 | // "If stopped then all jobs are processed immediately.", | ||
104 | // HandleControlCommand); | ||
105 | } | ||
106 | |||
107 | public void Start() | ||
108 | { | ||
109 | lock (this) | ||
110 | { | ||
111 | if (IsRunning) | ||
112 | return; | ||
113 | |||
114 | IsRunning = true; | ||
115 | |||
116 | m_finishedProcessingAfterStop.Reset(); | ||
117 | |||
118 | m_requestQueue = new BlockingCollection<Job>(new ConcurrentQueue<Job>(), 5000); | ||
119 | |||
120 | m_requestsWaitingStat = | ||
121 | new Stat( | ||
122 | "IncomingPacketAsyncRequestsWaiting", | ||
123 | "Number of incoming packets waiting for async processing in engine.", | ||
124 | "", | ||
125 | "", | ||
126 | "clientstack", | ||
127 | m_udpServer.Scene.Name, | ||
128 | StatType.Pull, | ||
129 | MeasuresOfInterest.None, | ||
130 | stat => stat.Value = m_requestQueue.Count, | ||
131 | StatVerbosity.Debug); | ||
132 | |||
133 | StatsManager.RegisterStat(m_requestsWaitingStat); | ||
134 | |||
135 | WorkManager.StartThread( | ||
136 | ProcessRequests, | ||
137 | string.Format("Incoming Packet Async Handling Engine Thread ({0})", m_udpServer.Scene.Name), | ||
138 | ThreadPriority.Normal, | ||
139 | false, | ||
140 | true, | ||
141 | null, | ||
142 | int.MaxValue); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | public void Stop() | ||
147 | { | ||
148 | lock (this) | ||
149 | { | ||
150 | try | ||
151 | { | ||
152 | if (!IsRunning) | ||
153 | return; | ||
154 | |||
155 | IsRunning = false; | ||
156 | |||
157 | int requestsLeft = m_requestQueue.Count; | ||
158 | |||
159 | if (requestsLeft <= 0) | ||
160 | { | ||
161 | m_cancelSource.Cancel(); | ||
162 | } | ||
163 | else | ||
164 | { | ||
165 | m_log.InfoFormat("[INCOMING PACKET ASYNC HANDLING ENGINE]: Waiting to write {0} events after stop.", requestsLeft); | ||
166 | |||
167 | while (requestsLeft > 0) | ||
168 | { | ||
169 | if (!m_finishedProcessingAfterStop.WaitOne(RequestProcessTimeoutOnStop)) | ||
170 | { | ||
171 | // After timeout no events have been written | ||
172 | if (requestsLeft == m_requestQueue.Count) | ||
173 | { | ||
174 | m_log.WarnFormat( | ||
175 | "[INCOMING PACKET ASYNC HANDLING ENGINE]: No requests processed after {0} ms wait. Discarding remaining {1} requests", | ||
176 | RequestProcessTimeoutOnStop, requestsLeft); | ||
177 | |||
178 | break; | ||
179 | } | ||
180 | } | ||
181 | |||
182 | requestsLeft = m_requestQueue.Count; | ||
183 | } | ||
184 | } | ||
185 | } | ||
186 | finally | ||
187 | { | ||
188 | m_cancelSource.Dispose(); | ||
189 | StatsManager.DeregisterStat(m_requestsWaitingStat); | ||
190 | m_requestsWaitingStat = null; | ||
191 | m_requestQueue = null; | ||
192 | } | ||
193 | } | ||
194 | } | ||
195 | |||
196 | public bool QueueRequest(string name, WaitCallback req, object o) | ||
197 | { | ||
198 | if (LogLevel >= 1) | ||
199 | m_log.DebugFormat("[INCOMING PACKET ASYNC HANDLING ENGINE]: Queued job {0}", name); | ||
200 | |||
201 | if (m_requestQueue.Count < m_requestQueue.BoundedCapacity) | ||
202 | { | ||
203 | // m_log.DebugFormat( | ||
204 | // "[OUTGOING QUEUE REFILL ENGINE]: Adding request for categories {0} for {1} in {2}", | ||
205 | // categories, client.AgentID, m_udpServer.Scene.Name); | ||
206 | |||
207 | m_requestQueue.Add(new Job(name, req, o)); | ||
208 | |||
209 | if (!m_warnOverMaxQueue) | ||
210 | m_warnOverMaxQueue = true; | ||
211 | |||
212 | return true; | ||
213 | } | ||
214 | else | ||
215 | { | ||
216 | if (m_warnOverMaxQueue) | ||
217 | { | ||
218 | // m_log.WarnFormat( | ||
219 | // "[JOB ENGINE]: Request queue at maximum capacity, not recording request from {0} in {1}", | ||
220 | // client.AgentID, m_udpServer.Scene.Name); | ||
221 | |||
222 | m_log.WarnFormat("[INCOMING PACKET ASYNC HANDLING ENGINE]: Request queue at maximum capacity, not recording job"); | ||
223 | |||
224 | m_warnOverMaxQueue = false; | ||
225 | } | ||
226 | |||
227 | return false; | ||
228 | } | ||
229 | } | ||
230 | |||
231 | private void ProcessRequests() | ||
232 | { | ||
233 | try | ||
234 | { | ||
235 | while (IsRunning || m_requestQueue.Count > 0) | ||
236 | { | ||
237 | m_currentJob = m_requestQueue.Take(m_cancelSource.Token); | ||
238 | |||
239 | // QueueEmpty callback = req.Client.OnQueueEmpty; | ||
240 | // | ||
241 | // if (callback != null) | ||
242 | // { | ||
243 | // try | ||
244 | // { | ||
245 | // callback(req.Categories); | ||
246 | // } | ||
247 | // catch (Exception e) | ||
248 | // { | ||
249 | // m_log.Error("[OUTGOING QUEUE REFILL ENGINE]: ProcessRequests(" + req.Categories + ") threw an exception: " + e.Message, e); | ||
250 | // } | ||
251 | // } | ||
252 | |||
253 | if (LogLevel >= 1) | ||
254 | m_log.DebugFormat("[INCOMING PACKET ASYNC HANDLING ENGINE]: Processing job {0}", m_currentJob.Name); | ||
255 | |||
256 | try | ||
257 | { | ||
258 | m_currentJob.Callback.Invoke(m_currentJob.O); | ||
259 | } | ||
260 | catch (Exception e) | ||
261 | { | ||
262 | m_log.Error( | ||
263 | string.Format( | ||
264 | "[INCOMING PACKET ASYNC HANDLING ENGINE]: Job {0} failed, continuing. Exception ", m_currentJob.Name), e); | ||
265 | } | ||
266 | |||
267 | if (LogLevel >= 1) | ||
268 | m_log.DebugFormat("[INCOMING PACKET ASYNC HANDLING ENGINE]: Processed job {0}", m_currentJob.Name); | ||
269 | |||
270 | m_currentJob = null; | ||
271 | } | ||
272 | } | ||
273 | catch (OperationCanceledException) | ||
274 | { | ||
275 | } | ||
276 | |||
277 | m_finishedProcessingAfterStop.Set(); | ||
278 | } | ||
279 | |||
280 | // private void HandleControlCommand(string module, string[] args) | ||
281 | // { | ||
282 | // // if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) | ||
283 | // // return; | ||
284 | // | ||
285 | // if (args.Length < 3) | ||
286 | // { | ||
287 | // MainConsole.Instance.Output("Usage: debug jobengine <stop|start|status|loglevel>"); | ||
288 | // return; | ||
289 | // } | ||
290 | // | ||
291 | // string subCommand = args[2]; | ||
292 | // | ||
293 | // if (subCommand == "stop") | ||
294 | // { | ||
295 | // Stop(); | ||
296 | // MainConsole.Instance.OutputFormat("Stopped job engine."); | ||
297 | // } | ||
298 | // else if (subCommand == "start") | ||
299 | // { | ||
300 | // Start(); | ||
301 | // MainConsole.Instance.OutputFormat("Started job engine."); | ||
302 | // } | ||
303 | // else if (subCommand == "status") | ||
304 | // { | ||
305 | // MainConsole.Instance.OutputFormat("Job engine running: {0}", IsRunning); | ||
306 | // MainConsole.Instance.OutputFormat("Current job {0}", m_currentJob != null ? m_currentJob.Name : "none"); | ||
307 | // MainConsole.Instance.OutputFormat( | ||
308 | // "Jobs waiting: {0}", IsRunning ? m_requestQueue.Count.ToString() : "n/a"); | ||
309 | // MainConsole.Instance.OutputFormat("Log Level: {0}", LogLevel); | ||
310 | // } | ||
311 | // | ||
312 | // else if (subCommand == "loglevel") | ||
313 | // { | ||
314 | // // int logLevel; | ||
315 | // int logLevel = int.Parse(args[3]); | ||
316 | // // if (ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out logLevel)) | ||
317 | // // { | ||
318 | // LogLevel = logLevel; | ||
319 | // MainConsole.Instance.OutputFormat("Set log level to {0}", LogLevel); | ||
320 | // // } | ||
321 | // } | ||
322 | // else | ||
323 | // { | ||
324 | // MainConsole.Instance.OutputFormat("Unrecognized job engine subcommand {0}", subCommand); | ||
325 | // } | ||
326 | // } | ||
327 | } | ||
328 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index c839c05..85f9d68 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | |||
@@ -648,12 +648,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
648 | /// <returns>true if the handler was added. This is currently always the case.</returns> | 648 | /// <returns>true if the handler was added. This is currently always the case.</returns> |
649 | public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync) | 649 | public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync) |
650 | { | 650 | { |
651 | return AddLocalPacketHandler(packetType, handler, doAsync, false); | ||
652 | } | ||
653 | |||
654 | /// <summary> | ||
655 | /// Add a handler for the given packet type. | ||
656 | /// </summary> | ||
657 | /// <param name="packetType"></param> | ||
658 | /// <param name="handler"></param> | ||
659 | /// <param name="doAsync"> | ||
660 | /// If true, when the packet is received handle it on a different thread. Whether this is given direct to | ||
661 | /// a threadpool thread or placed in a queue depends on the inEngine parameter. | ||
662 | /// </param> | ||
663 | /// <param name="inEngine"> | ||
664 | /// If async is false then this parameter is ignored. | ||
665 | /// If async is true and inEngine is false, then the packet is sent directly to a | ||
666 | /// threadpool thread. | ||
667 | /// If async is true and inEngine is true, then the packet is sent to the IncomingPacketAsyncHandlingEngine. | ||
668 | /// This may result in slower handling but reduces the risk of overloading the simulator when there are many | ||
669 | /// simultaneous async requests. | ||
670 | /// </param> | ||
671 | /// <returns>true if the handler was added. This is currently always the case.</returns> | ||
672 | public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync, bool inEngine) | ||
673 | { | ||
651 | bool result = false; | 674 | bool result = false; |
652 | lock (m_packetHandlers) | 675 | lock (m_packetHandlers) |
653 | { | 676 | { |
654 | if (!m_packetHandlers.ContainsKey(packetType)) | 677 | if (!m_packetHandlers.ContainsKey(packetType)) |
655 | { | 678 | { |
656 | m_packetHandlers.Add(packetType, new PacketProcessor() { method = handler, Async = doAsync }); | 679 | m_packetHandlers.Add( |
680 | packetType, new PacketProcessor() { method = handler, Async = doAsync, InEngine = inEngine }); | ||
657 | result = true; | 681 | result = true; |
658 | } | 682 | } |
659 | } | 683 | } |
@@ -688,21 +712,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
688 | PacketProcessor pprocessor; | 712 | PacketProcessor pprocessor; |
689 | if (m_packetHandlers.TryGetValue(packet.Type, out pprocessor)) | 713 | if (m_packetHandlers.TryGetValue(packet.Type, out pprocessor)) |
690 | { | 714 | { |
715 | ClientInfo cinfo = UDPClient.GetClientInfo(); | ||
716 | |||
691 | //there is a local handler for this packet type | 717 | //there is a local handler for this packet type |
692 | if (pprocessor.Async) | 718 | if (pprocessor.Async) |
693 | { | 719 | { |
694 | ClientInfo cinfo = UDPClient.GetClientInfo(); | ||
695 | if (!cinfo.AsyncRequests.ContainsKey(packet.Type.ToString())) | 720 | if (!cinfo.AsyncRequests.ContainsKey(packet.Type.ToString())) |
696 | cinfo.AsyncRequests[packet.Type.ToString()] = 0; | 721 | cinfo.AsyncRequests[packet.Type.ToString()] = 0; |
697 | cinfo.AsyncRequests[packet.Type.ToString()]++; | 722 | cinfo.AsyncRequests[packet.Type.ToString()]++; |
698 | 723 | ||
699 | object obj = new AsyncPacketProcess(this, pprocessor.method, packet); | 724 | object obj = new AsyncPacketProcess(this, pprocessor.method, packet); |
700 | Util.FireAndForget(ProcessSpecificPacketAsync, obj, packet.Type.ToString()); | 725 | |
726 | if (pprocessor.InEngine) | ||
727 | m_udpServer.IpahEngine.QueueRequest( | ||
728 | packet.Type.ToString(), | ||
729 | ProcessSpecificPacketAsync, | ||
730 | obj); | ||
731 | else | ||
732 | Util.FireAndForget(ProcessSpecificPacketAsync, obj, packet.Type.ToString()); | ||
733 | |||
701 | result = true; | 734 | result = true; |
702 | } | 735 | } |
703 | else | 736 | else |
704 | { | 737 | { |
705 | ClientInfo cinfo = UDPClient.GetClientInfo(); | ||
706 | if (!cinfo.SyncRequests.ContainsKey(packet.Type.ToString())) | 738 | if (!cinfo.SyncRequests.ContainsKey(packet.Type.ToString())) |
707 | cinfo.SyncRequests[packet.Type.ToString()] = 0; | 739 | cinfo.SyncRequests[packet.Type.ToString()] = 0; |
708 | cinfo.SyncRequests[packet.Type.ToString()]++; | 740 | cinfo.SyncRequests[packet.Type.ToString()]++; |
@@ -1161,7 +1193,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1161 | /// <param name="map">heightmap</param> | 1193 | /// <param name="map">heightmap</param> |
1162 | public virtual void SendLayerData(float[] map) | 1194 | public virtual void SendLayerData(float[] map) |
1163 | { | 1195 | { |
1164 | Util.FireAndForget(DoSendLayerData, m_scene.Heightmap.GetTerrainData()); | 1196 | Util.FireAndForget(DoSendLayerData, m_scene.Heightmap.GetTerrainData(), "LLClientView.DoSendLayerData"); |
1165 | } | 1197 | } |
1166 | 1198 | ||
1167 | /// <summary> | 1199 | /// <summary> |
@@ -1373,7 +1405,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1373 | /// <param name="windSpeeds">16x16 array of wind speeds</param> | 1405 | /// <param name="windSpeeds">16x16 array of wind speeds</param> |
1374 | public virtual void SendWindData(Vector2[] windSpeeds) | 1406 | public virtual void SendWindData(Vector2[] windSpeeds) |
1375 | { | 1407 | { |
1376 | Util.FireAndForget(DoSendWindData, windSpeeds); | 1408 | Util.FireAndForget(DoSendWindData, windSpeeds, "LLClientView.SendWindData"); |
1377 | } | 1409 | } |
1378 | 1410 | ||
1379 | /// <summary> | 1411 | /// <summary> |
@@ -1382,7 +1414,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1382 | /// <param name="windSpeeds">16x16 array of cloud densities</param> | 1414 | /// <param name="windSpeeds">16x16 array of cloud densities</param> |
1383 | public virtual void SendCloudData(float[] cloudDensity) | 1415 | public virtual void SendCloudData(float[] cloudDensity) |
1384 | { | 1416 | { |
1385 | Util.FireAndForget(DoSendCloudData, cloudDensity); | 1417 | Util.FireAndForget(DoSendCloudData, cloudDensity, "LLClientView.SendCloudData"); |
1386 | } | 1418 | } |
1387 | 1419 | ||
1388 | /// <summary> | 1420 | /// <summary> |
@@ -3834,11 +3866,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3834 | /// </summary> | 3866 | /// </summary> |
3835 | public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) | 3867 | public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) |
3836 | { | 3868 | { |
3837 | //double priority = m_prioritizer.GetUpdatePriority(this, entity); | 3869 | if (entity.UUID == m_agentId && !updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) |
3838 | uint priority = m_prioritizer.GetUpdatePriority(this, entity); | 3870 | { |
3871 | ImprovedTerseObjectUpdatePacket packet | ||
3872 | = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); | ||
3839 | 3873 | ||
3840 | lock (m_entityUpdates.SyncRoot) | 3874 | packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; |
3841 | m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); | 3875 | packet.RegionData.TimeDilation = Utils.FloatToUInt16(1, 0.0f, 1.0f); |
3876 | packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; | ||
3877 | packet.ObjectData[0] = CreateImprovedTerseBlock(entity, false); | ||
3878 | OutPacket(packet, ThrottleOutPacketType.Unknown, true); | ||
3879 | } | ||
3880 | else | ||
3881 | { | ||
3882 | //double priority = m_prioritizer.GetUpdatePriority(this, entity); | ||
3883 | uint priority = m_prioritizer.GetUpdatePriority(this, entity); | ||
3884 | |||
3885 | lock (m_entityUpdates.SyncRoot) | ||
3886 | m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); | ||
3887 | } | ||
3842 | } | 3888 | } |
3843 | 3889 | ||
3844 | /// <summary> | 3890 | /// <summary> |
@@ -5540,10 +5586,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5540 | AddLocalPacketHandler(PacketType.ParcelBuy, HandleParcelBuyRequest, false); | 5586 | AddLocalPacketHandler(PacketType.ParcelBuy, HandleParcelBuyRequest, false); |
5541 | AddLocalPacketHandler(PacketType.UUIDGroupNameRequest, HandleUUIDGroupNameRequest); | 5587 | AddLocalPacketHandler(PacketType.UUIDGroupNameRequest, HandleUUIDGroupNameRequest); |
5542 | AddLocalPacketHandler(PacketType.ObjectGroup, HandleObjectGroupRequest); | 5588 | AddLocalPacketHandler(PacketType.ObjectGroup, HandleObjectGroupRequest); |
5543 | AddLocalPacketHandler(PacketType.GenericMessage, HandleGenericMessage); | 5589 | AddLocalPacketHandler(PacketType.GenericMessage, HandleGenericMessage, true, true); |
5544 | AddLocalPacketHandler(PacketType.AvatarPropertiesRequest, HandleAvatarPropertiesRequest); | 5590 | AddLocalPacketHandler(PacketType.AvatarPropertiesRequest, HandleAvatarPropertiesRequest, true, true); |
5545 | AddLocalPacketHandler(PacketType.ChatFromViewer, HandleChatFromViewer); | 5591 | AddLocalPacketHandler(PacketType.ChatFromViewer, HandleChatFromViewer); |
5546 | AddLocalPacketHandler(PacketType.AvatarPropertiesUpdate, HandlerAvatarPropertiesUpdate); | 5592 | AddLocalPacketHandler(PacketType.AvatarPropertiesUpdate, HandlerAvatarPropertiesUpdate, true, true); |
5547 | AddLocalPacketHandler(PacketType.ScriptDialogReply, HandlerScriptDialogReply); | 5593 | AddLocalPacketHandler(PacketType.ScriptDialogReply, HandlerScriptDialogReply); |
5548 | AddLocalPacketHandler(PacketType.ImprovedInstantMessage, HandlerImprovedInstantMessage); | 5594 | AddLocalPacketHandler(PacketType.ImprovedInstantMessage, HandlerImprovedInstantMessage); |
5549 | AddLocalPacketHandler(PacketType.AcceptFriendship, HandlerAcceptFriendship); | 5595 | AddLocalPacketHandler(PacketType.AcceptFriendship, HandlerAcceptFriendship); |
@@ -5728,8 +5774,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
5728 | AddLocalPacketHandler(PacketType.PickDelete, HandlePickDelete); | 5774 | AddLocalPacketHandler(PacketType.PickDelete, HandlePickDelete); |
5729 | AddLocalPacketHandler(PacketType.PickGodDelete, HandlePickGodDelete); | 5775 | AddLocalPacketHandler(PacketType.PickGodDelete, HandlePickGodDelete); |
5730 | AddLocalPacketHandler(PacketType.PickInfoUpdate, HandlePickInfoUpdate); | 5776 | AddLocalPacketHandler(PacketType.PickInfoUpdate, HandlePickInfoUpdate); |
5731 | AddLocalPacketHandler(PacketType.AvatarNotesUpdate, HandleAvatarNotesUpdate); | 5777 | AddLocalPacketHandler(PacketType.AvatarNotesUpdate, HandleAvatarNotesUpdate, true, true); |
5732 | AddLocalPacketHandler(PacketType.AvatarInterestsUpdate, HandleAvatarInterestsUpdate); | 5778 | AddLocalPacketHandler(PacketType.AvatarInterestsUpdate, HandleAvatarInterestsUpdate, true, true); |
5733 | AddLocalPacketHandler(PacketType.GrantUserRights, HandleGrantUserRights); | 5779 | AddLocalPacketHandler(PacketType.GrantUserRights, HandleGrantUserRights); |
5734 | AddLocalPacketHandler(PacketType.PlacesQuery, HandlePlacesQuery); | 5780 | AddLocalPacketHandler(PacketType.PlacesQuery, HandlePlacesQuery); |
5735 | AddLocalPacketHandler(PacketType.UpdateMuteListEntry, HandleUpdateMuteListEntry); | 5781 | AddLocalPacketHandler(PacketType.UpdateMuteListEntry, HandleUpdateMuteListEntry); |
@@ -8079,7 +8125,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
8079 | { | 8125 | { |
8080 | // This requests the asset if needed | 8126 | // This requests the asset if needed |
8081 | HandleSimInventoryTransferRequestWithPermsCheck(sender, transfer); | 8127 | HandleSimInventoryTransferRequestWithPermsCheck(sender, transfer); |
8082 | }); | 8128 | }, null, "LLClientView.HandleTransferRequest"); |
8129 | |||
8083 | return true; | 8130 | return true; |
8084 | } | 8131 | } |
8085 | } | 8132 | } |
@@ -12786,8 +12833,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
12786 | 12833 | ||
12787 | public struct PacketProcessor | 12834 | public struct PacketProcessor |
12788 | { | 12835 | { |
12789 | public PacketMethod method; | 12836 | /// <summary> |
12790 | public bool Async; | 12837 | /// Packet handling method. |
12838 | /// </summary> | ||
12839 | public PacketMethod method { get; set; } | ||
12840 | |||
12841 | /// <summary> | ||
12842 | /// Should this packet be handled asynchronously? | ||
12843 | /// </summary> | ||
12844 | public bool Async { get; set; } | ||
12845 | |||
12846 | /// <summary> | ||
12847 | /// If async is true, should this packet be handled in the async engine or given directly to a threadpool | ||
12848 | /// thread? | ||
12849 | /// </summary> | ||
12850 | public bool InEngine { get; set; } | ||
12791 | } | 12851 | } |
12792 | 12852 | ||
12793 | public class AsyncPacketProcess | 12853 | public class AsyncPacketProcess |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index d8ca343..8f14806 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs | |||
@@ -97,7 +97,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
97 | { | 97 | { |
98 | m_throttleDebugLevel = value; | 98 | m_throttleDebugLevel = value; |
99 | m_throttleClient.DebugLevel = m_throttleDebugLevel; | 99 | m_throttleClient.DebugLevel = m_throttleDebugLevel; |
100 | m_throttleCategory.DebugLevel = m_throttleDebugLevel; | ||
101 | foreach (TokenBucket tb in m_throttleCategories) | 100 | foreach (TokenBucket tb in m_throttleCategories) |
102 | tb.DebugLevel = m_throttleDebugLevel; | 101 | tb.DebugLevel = m_throttleDebugLevel; |
103 | } | 102 | } |
@@ -172,8 +171,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
172 | get { return m_throttleClient; } | 171 | get { return m_throttleClient; } |
173 | } | 172 | } |
174 | 173 | ||
175 | /// <summary>Throttle bucket for this agent's connection</summary> | ||
176 | private readonly TokenBucket m_throttleCategory; | ||
177 | /// <summary>Throttle buckets for each packet category</summary> | 174 | /// <summary>Throttle buckets for each packet category</summary> |
178 | private readonly TokenBucket[] m_throttleCategories; | 175 | private readonly TokenBucket[] m_throttleCategories; |
179 | /// <summary>Outgoing queues for throttled packets</summary> | 176 | /// <summary>Outgoing queues for throttled packets</summary> |
@@ -232,13 +229,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
232 | m_throttleClient | 229 | m_throttleClient |
233 | = new AdaptiveTokenBucket( | 230 | = new AdaptiveTokenBucket( |
234 | string.Format("adaptive throttle for {0} in {1}", AgentID, server.Scene.Name), | 231 | string.Format("adaptive throttle for {0} in {1}", AgentID, server.Scene.Name), |
235 | parentThrottle, rates.Total, rates.AdaptiveThrottlesEnabled); | 232 | parentThrottle, 0, rates.Total, rates.AdaptiveThrottlesEnabled); |
236 | |||
237 | // Create a token bucket throttle for the total category with the client bucket as a throttle | ||
238 | m_throttleCategory | ||
239 | = new TokenBucket( | ||
240 | string.Format("total throttle for {0} in {1}", AgentID, server.Scene.Name), | ||
241 | m_throttleClient, 0); | ||
242 | 233 | ||
243 | // Create an array of token buckets for this clients different throttle categories | 234 | // Create an array of token buckets for this clients different throttle categories |
244 | m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; | 235 | m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; |
@@ -256,7 +247,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
256 | m_throttleCategories[i] | 247 | m_throttleCategories[i] |
257 | = new TokenBucket( | 248 | = new TokenBucket( |
258 | string.Format("{0} throttle for {1} in {2}", type, AgentID, server.Scene.Name), | 249 | string.Format("{0} throttle for {1} in {2}", type, AgentID, server.Scene.Name), |
259 | m_throttleCategory, rates.GetRate(type)); | 250 | m_throttleClient, rates.GetRate(type), 0); |
260 | } | 251 | } |
261 | 252 | ||
262 | // Default the retransmission timeout to one second | 253 | // Default the retransmission timeout to one second |
@@ -301,7 +292,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
301 | m_info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; | 292 | m_info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; |
302 | m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; | 293 | m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; |
303 | m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; | 294 | m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; |
304 | m_info.totalThrottle = (int)m_throttleCategory.DripRate; | 295 | m_info.totalThrottle = (int)m_throttleClient.DripRate; |
296 | m_info.targetThrottle = (int)m_throttleClient.TargetDripRate; | ||
305 | m_info.maxThrottle = (int)m_throttleClient.MaxDripRate; | 297 | m_info.maxThrottle = (int)m_throttleClient.MaxDripRate; |
306 | 298 | ||
307 | return m_info; | 299 | return m_info; |
@@ -320,6 +312,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
320 | } | 312 | } |
321 | 313 | ||
322 | /// <summary> | 314 | /// <summary> |
315 | /// Get the total number of pakcets queued for this client. | ||
316 | /// </summary> | ||
317 | /// <returns></returns> | ||
318 | public int GetTotalPacketsQueuedCount() | ||
319 | { | ||
320 | int total = 0; | ||
321 | |||
322 | for (int i = 0; i <= (int)ThrottleOutPacketType.Asset; i++) | ||
323 | total += m_packetOutboxes[i].Count; | ||
324 | |||
325 | return total; | ||
326 | } | ||
327 | |||
328 | /// <summary> | ||
329 | /// Get the number of packets queued for the given throttle type. | ||
330 | /// </summary> | ||
331 | /// <returns></returns> | ||
332 | /// <param name="throttleType"></param> | ||
333 | public int GetPacketsQueuedCount(ThrottleOutPacketType throttleType) | ||
334 | { | ||
335 | if ((int)throttleType > 0) | ||
336 | return m_packetOutboxes[(int)throttleType].Count; | ||
337 | else | ||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | /// <summary> | ||
323 | /// Return statistics information about client packet queues. | 342 | /// Return statistics information about client packet queues. |
324 | /// </summary> | 343 | /// </summary> |
325 | /// <remarks> | 344 | /// <remarks> |
@@ -388,6 +407,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
388 | int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | 407 | int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; |
389 | int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); | 408 | int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); |
390 | 409 | ||
410 | if (ThrottleDebugLevel > 0) | ||
411 | { | ||
412 | long total = resend + land + wind + cloud + task + texture + asset; | ||
413 | m_log.DebugFormat( | ||
414 | "[LLUDPCLIENT]: {0} is setting throttles in {1} to Resend={2}, Land={3}, Wind={4}, Cloud={5}, Task={6}, Texture={7}, Asset={8}, TOTAL = {9}", | ||
415 | AgentID, m_udpServer.Scene.Name, resend, land, wind, cloud, task, texture, asset, total); | ||
416 | } | ||
417 | |||
391 | // Make sure none of the throttles are set below our packet MTU, | 418 | // Make sure none of the throttles are set below our packet MTU, |
392 | // otherwise a throttle could become permanently clogged | 419 | // otherwise a throttle could become permanently clogged |
393 | resend = Math.Max(resend, LLUDPServer.MTU); | 420 | resend = Math.Max(resend, LLUDPServer.MTU); |
@@ -407,11 +434,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
407 | //int total = resend + land + wind + cloud + task + texture + asset; | 434 | //int total = resend + land + wind + cloud + task + texture + asset; |
408 | 435 | ||
409 | if (ThrottleDebugLevel > 0) | 436 | if (ThrottleDebugLevel > 0) |
437 | { | ||
438 | long total = resend + land + wind + cloud + task + texture + asset; | ||
410 | m_log.DebugFormat( | 439 | m_log.DebugFormat( |
411 | "[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}", | 440 | "[LLUDPCLIENT]: {0} is setting throttles in {1} to Resend={2}, Land={3}, Wind={4}, Cloud={5}, Task={6}, Texture={7}, Asset={8}, TOTAL = {9}", |
412 | AgentID, m_udpServer.Scene.Name, resend, land, wind, cloud, task, texture, asset); | 441 | AgentID, m_udpServer.Scene.Name, resend, land, wind, cloud, task, texture, asset, total); |
442 | } | ||
413 | 443 | ||
414 | // Update the token buckets with new throttle values | 444 | // Update the token buckets with new throttle values |
445 | if (m_throttleClient.AdaptiveEnabled) | ||
446 | { | ||
447 | long total = resend + land + wind + cloud + task + texture + asset; | ||
448 | m_throttleClient.TargetDripRate = total; | ||
449 | } | ||
450 | |||
415 | TokenBucket bucket; | 451 | TokenBucket bucket; |
416 | 452 | ||
417 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; | 453 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; |
@@ -696,7 +732,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
696 | if (!m_udpServer.OqrEngine.IsRunning) | 732 | if (!m_udpServer.OqrEngine.IsRunning) |
697 | { | 733 | { |
698 | // Asynchronously run the callback | 734 | // Asynchronously run the callback |
699 | Util.FireAndForget(FireQueueEmpty, categories); | 735 | Util.FireAndForget(FireQueueEmpty, categories, "LLUDPClient.BeginFireQueueEmpty"); |
700 | } | 736 | } |
701 | else | 737 | else |
702 | { | 738 | { |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 9757d35..2f97516 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | |||
@@ -34,7 +34,6 @@ using System.Net.Sockets; | |||
34 | using System.Reflection; | 34 | using System.Reflection; |
35 | using System.Threading; | 35 | using System.Threading; |
36 | using log4net; | 36 | using log4net; |
37 | using NDesk.Options; | ||
38 | using Nini.Config; | 37 | using Nini.Config; |
39 | using OpenMetaverse.Packets; | 38 | using OpenMetaverse.Packets; |
40 | using OpenSim.Framework; | 39 | using OpenSim.Framework; |
@@ -222,6 +221,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
222 | /// </summary> | 221 | /// </summary> |
223 | public int DefaultClientPacketDebugLevel { get; set; } | 222 | public int DefaultClientPacketDebugLevel { get; set; } |
224 | 223 | ||
224 | /// <summary> | ||
225 | /// If set then all inbound agent updates are discarded. For debugging purposes. | ||
226 | /// discard agent update. | ||
227 | /// </summary> | ||
228 | public bool DiscardInboundAgentUpdates { get; set; } | ||
229 | |||
225 | /// <summary>The measured resolution of Environment.TickCount</summary> | 230 | /// <summary>The measured resolution of Environment.TickCount</summary> |
226 | public readonly float TickCountResolution; | 231 | public readonly float TickCountResolution; |
227 | 232 | ||
@@ -238,12 +243,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
238 | /// <summary>Incoming packets that are awaiting handling</summary> | 243 | /// <summary>Incoming packets that are awaiting handling</summary> |
239 | private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); | 244 | private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); |
240 | 245 | ||
241 | /// <summary></summary> | ||
242 | //private UDPClientCollection m_clients = new UDPClientCollection(); | ||
243 | /// <summary>Bandwidth throttle for this UDP server</summary> | 246 | /// <summary>Bandwidth throttle for this UDP server</summary> |
244 | protected TokenBucket m_throttle; | 247 | public TokenBucket Throttle { get; private set; } |
245 | 248 | ||
246 | /// <summary>Bandwidth throttle rates for this UDP server</summary> | 249 | /// <summary>Per client throttle rates enforced by this server</summary> |
250 | /// <remarks> | ||
251 | /// If the total rate is non-zero, then this is the maximum total throttle setting that any client can ever have. | ||
252 | /// The other rates (resend, asset, etc.) are the defaults for a new client and can be changed (and usually | ||
253 | /// do get changed immediately). They do not need to sum to the total. | ||
254 | /// </remarks> | ||
247 | public ThrottleRates ThrottleRates { get; private set; } | 255 | public ThrottleRates ThrottleRates { get; private set; } |
248 | 256 | ||
249 | /// <summary>Manages authentication for agent circuits</summary> | 257 | /// <summary>Manages authentication for agent circuits</summary> |
@@ -356,6 +364,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
356 | private IClientAPI m_currentIncomingClient; | 364 | private IClientAPI m_currentIncomingClient; |
357 | 365 | ||
358 | /// <summary> | 366 | /// <summary> |
367 | /// Queue some low priority but potentially high volume async requests so that they don't overwhelm available | ||
368 | /// threadpool threads. | ||
369 | /// </summary> | ||
370 | public IncomingPacketAsyncHandlingEngine IpahEngine { get; private set; } | ||
371 | |||
372 | /// <summary> | ||
359 | /// Experimental facility to run queue empty processing within a controlled number of threads rather than | 373 | /// Experimental facility to run queue empty processing within a controlled number of threads rather than |
360 | /// requiring massive numbers of short-lived threads from the threadpool when there are a high number of | 374 | /// requiring massive numbers of short-lived threads from the threadpool when there are a high number of |
361 | /// connections. | 375 | /// connections. |
@@ -439,13 +453,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
439 | // = new TokenBucket( | 453 | // = new TokenBucket( |
440 | // string.Format("server throttle bucket for {0}", Scene.Name), null, sceneThrottleBps); | 454 | // string.Format("server throttle bucket for {0}", Scene.Name), null, sceneThrottleBps); |
441 | 455 | ||
442 | m_throttle = new TokenBucket("server throttle bucket", null, sceneThrottleBps); | 456 | Throttle = new TokenBucket("server throttle bucket", null, 0, sceneThrottleBps); |
443 | 457 | ||
444 | ThrottleRates = new ThrottleRates(configSource); | 458 | ThrottleRates = new ThrottleRates(configSource); |
445 | 459 | ||
446 | if (usePools) | 460 | if (usePools) |
447 | EnablePools(); | 461 | EnablePools(); |
448 | 462 | ||
463 | IpahEngine = new IncomingPacketAsyncHandlingEngine(this); | ||
449 | OqrEngine = new OutgoingQueueRefillEngine(this); | 464 | OqrEngine = new OutgoingQueueRefillEngine(this); |
450 | } | 465 | } |
451 | 466 | ||
@@ -453,12 +468,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
453 | { | 468 | { |
454 | StartInbound(); | 469 | StartInbound(); |
455 | StartOutbound(); | 470 | StartOutbound(); |
471 | IpahEngine.Start(); | ||
456 | OqrEngine.Start(); | 472 | OqrEngine.Start(); |
457 | 473 | ||
458 | m_elapsedMSSinceLastStatReport = Environment.TickCount; | 474 | m_elapsedMSSinceLastStatReport = Environment.TickCount; |
459 | } | 475 | } |
460 | 476 | ||
461 | private void StartInbound() | 477 | public void StartInbound() |
462 | { | 478 | { |
463 | m_log.InfoFormat( | 479 | m_log.InfoFormat( |
464 | "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}", | 480 | "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}", |
@@ -467,7 +483,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
467 | base.StartInbound(m_recvBufferSize, m_asyncPacketHandling); | 483 | base.StartInbound(m_recvBufferSize, m_asyncPacketHandling); |
468 | 484 | ||
469 | // This thread will process the packets received that are placed on the packetInbox | 485 | // This thread will process the packets received that are placed on the packetInbox |
470 | Watchdog.StartThread( | 486 | WorkManager.StartThread( |
471 | IncomingPacketHandler, | 487 | IncomingPacketHandler, |
472 | string.Format("Incoming Packets ({0})", Scene.Name), | 488 | string.Format("Incoming Packets ({0})", Scene.Name), |
473 | ThreadPriority.Normal, | 489 | ThreadPriority.Normal, |
@@ -477,13 +493,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
477 | Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); | 493 | Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); |
478 | } | 494 | } |
479 | 495 | ||
480 | private new void StartOutbound() | 496 | public override void StartOutbound() |
481 | { | 497 | { |
482 | m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server"); | 498 | m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server"); |
483 | 499 | ||
484 | base.StartOutbound(); | 500 | base.StartOutbound(); |
485 | 501 | ||
486 | Watchdog.StartThread( | 502 | WorkManager.StartThread( |
487 | OutgoingPacketHandler, | 503 | OutgoingPacketHandler, |
488 | string.Format("Outgoing Packets ({0})", Scene.Name), | 504 | string.Format("Outgoing Packets ({0})", Scene.Name), |
489 | ThreadPriority.Normal, | 505 | ThreadPriority.Normal, |
@@ -498,10 +514,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
498 | m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + Scene.Name); | 514 | m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + Scene.Name); |
499 | base.StopOutbound(); | 515 | base.StopOutbound(); |
500 | base.StopInbound(); | 516 | base.StopInbound(); |
517 | IpahEngine.Stop(); | ||
501 | OqrEngine.Stop(); | 518 | OqrEngine.Stop(); |
502 | } | 519 | } |
503 | 520 | ||
504 | protected override bool EnablePools() | 521 | public override bool EnablePools() |
505 | { | 522 | { |
506 | if (!UsePools) | 523 | if (!UsePools) |
507 | { | 524 | { |
@@ -515,7 +532,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
515 | return false; | 532 | return false; |
516 | } | 533 | } |
517 | 534 | ||
518 | protected override bool DisablePools() | 535 | public override bool DisablePools() |
519 | { | 536 | { |
520 | if (UsePools) | 537 | if (UsePools) |
521 | { | 538 | { |
@@ -535,7 +552,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
535 | /// This is a seperate method so that it can be called once we have an m_scene to distinguish different scene | 552 | /// This is a seperate method so that it can be called once we have an m_scene to distinguish different scene |
536 | /// stats. | 553 | /// stats. |
537 | /// </summary> | 554 | /// </summary> |
538 | private void EnablePoolStats() | 555 | protected internal void EnablePoolStats() |
539 | { | 556 | { |
540 | m_poolCountStat | 557 | m_poolCountStat |
541 | = new Stat( | 558 | = new Stat( |
@@ -569,7 +586,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
569 | /// <summary> | 586 | /// <summary> |
570 | /// Disables pool stats. | 587 | /// Disables pool stats. |
571 | /// </summary> | 588 | /// </summary> |
572 | private void DisablePoolStats() | 589 | protected internal void DisablePoolStats() |
573 | { | 590 | { |
574 | StatsManager.DeregisterStat(m_poolCountStat); | 591 | StatsManager.DeregisterStat(m_poolCountStat); |
575 | m_poolCountStat = null; | 592 | m_poolCountStat = null; |
@@ -683,434 +700,45 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
683 | StatType.Pull, | 700 | StatType.Pull, |
684 | stat => stat.Value = PacketPool.Instance.BlocksPooled, | 701 | stat => stat.Value = PacketPool.Instance.BlocksPooled, |
685 | StatVerbosity.Debug)); | 702 | StatVerbosity.Debug)); |
703 | |||
704 | StatsManager.RegisterStat( | ||
705 | new Stat( | ||
706 | "OutgoingPacketsQueuedCount", | ||
707 | "Packets queued for outgoing send", | ||
708 | "Number of queued outgoing packets across all connections", | ||
709 | "", | ||
710 | "clientstack", | ||
711 | Scene.Name, | ||
712 | StatType.Pull, | ||
713 | MeasuresOfInterest.AverageChangeOverTime, | ||
714 | stat => stat.Value = GetTotalQueuedOutgoingPackets(), | ||
715 | StatVerbosity.Info)); | ||
686 | 716 | ||
687 | // We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by | 717 | // We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by |
688 | // scene name | 718 | // scene name |
689 | if (UsePools) | 719 | if (UsePools) |
690 | EnablePoolStats(); | 720 | EnablePoolStats(); |
691 | 721 | ||
692 | MainConsole.Instance.Commands.AddCommand( | 722 | LLUDPServerCommands commands = new LLUDPServerCommands(MainConsole.Instance, this); |
693 | "Debug", false, "debug lludp packet", | 723 | commands.Register(); |
694 | "debug lludp packet [--default | --all] <level> [<avatar-first-name> <avatar-last-name>]", | ||
695 | "Turn on packet debugging. This logs information when the client stack hands a processed packet off to downstream code or when upstream code first requests that a certain packet be sent.", | ||
696 | "If level > 255 then all incoming and outgoing packets are logged.\n" | ||
697 | + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n" | ||
698 | + "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n" | ||
699 | + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n" | ||
700 | + "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n" | ||
701 | + "If level <= 0 then no packets are logged.\n" | ||
702 | + "If --default is specified then the level becomes the default logging level for all subsequent agents.\n" | ||
703 | + "If --all is specified then the level becomes the default logging level for all current and subsequent agents.\n" | ||
704 | + "In these cases, you cannot also specify an avatar name.\n" | ||
705 | + "If an avatar name is given then only packets from that avatar are logged.", | ||
706 | HandlePacketCommand); | ||
707 | |||
708 | MainConsole.Instance.Commands.AddCommand( | ||
709 | "Debug", false, "debug lludp data out", | ||
710 | "debug lludp data out <level> <avatar-first-name> <avatar-last-name>\"", | ||
711 | "Turn on debugging for final outgoing data to the given user's client.", | ||
712 | "This operates at a much lower level than the packet command and prints out available details when the data is actually sent.\n" | ||
713 | + "If level > 0 then information about all outgoing UDP data for this avatar is logged.\n" | ||
714 | + "If level <= 0 then no information about outgoing UDP data for this avatar is logged.", | ||
715 | HandleDataCommand); | ||
716 | |||
717 | MainConsole.Instance.Commands.AddCommand( | ||
718 | "Debug", false, "debug lludp drop", | ||
719 | "debug lludp drop <in|out> <add|remove> <packet-name>", | ||
720 | "Drop all in or outbound packets that match the given name", | ||
721 | "For test purposes.", | ||
722 | HandleDropCommand); | ||
723 | |||
724 | MainConsole.Instance.Commands.AddCommand( | ||
725 | "Debug", | ||
726 | false, | ||
727 | "debug lludp start", | ||
728 | "debug lludp start <in|out|all>", | ||
729 | "Control LLUDP packet processing.", | ||
730 | "No effect if packet processing has already started.\n" | ||
731 | + "in - start inbound processing.\n" | ||
732 | + "out - start outbound processing.\n" | ||
733 | + "all - start in and outbound processing.\n", | ||
734 | HandleStartCommand); | ||
735 | |||
736 | MainConsole.Instance.Commands.AddCommand( | ||
737 | "Debug", | ||
738 | false, | ||
739 | "debug lludp stop", | ||
740 | "debug lludp stop <in|out|all>", | ||
741 | "Stop LLUDP packet processing.", | ||
742 | "No effect if packet processing has already stopped.\n" | ||
743 | + "in - stop inbound processing.\n" | ||
744 | + "out - stop outbound processing.\n" | ||
745 | + "all - stop in and outbound processing.\n", | ||
746 | HandleStopCommand); | ||
747 | |||
748 | MainConsole.Instance.Commands.AddCommand( | ||
749 | "Debug", | ||
750 | false, | ||
751 | "debug lludp pool", | ||
752 | "debug lludp pool <on|off>", | ||
753 | "Turn object pooling within the lludp component on or off.", | ||
754 | HandlePoolCommand); | ||
755 | |||
756 | MainConsole.Instance.Commands.AddCommand( | ||
757 | "Debug", | ||
758 | false, | ||
759 | "debug lludp status", | ||
760 | "debug lludp status", | ||
761 | "Return status of LLUDP packet processing.", | ||
762 | HandleStatusCommand); | ||
763 | |||
764 | MainConsole.Instance.Commands.AddCommand( | ||
765 | "Debug", | ||
766 | false, | ||
767 | "debug lludp throttle log", | ||
768 | "debug lludp throttle log <level> <avatar-first-name> <avatar-last-name>", | ||
769 | "Change debug logging level for throttles.", | ||
770 | "If level >= 0 then throttle debug logging is performed.\n" | ||
771 | + "If level <= 0 then no throttle debug logging is performed.", | ||
772 | HandleThrottleCommand); | ||
773 | |||
774 | MainConsole.Instance.Commands.AddCommand( | ||
775 | "Debug", | ||
776 | false, | ||
777 | "debug lludp throttle status", | ||
778 | "debug lludp throttle status <avatar-first-name> <avatar-last-name>", | ||
779 | "Return status information about throttles.", | ||
780 | HandleThrottleStatusCommand); | ||
781 | |||
782 | MainConsole.Instance.Commands.AddCommand( | ||
783 | "Debug", | ||
784 | false, | ||
785 | "debug lludp toggle agentupdate", | ||
786 | "debug lludp toggle agentupdate", | ||
787 | "Toggle whether agentupdate packets are processed or simply discarded.", | ||
788 | HandleAgentUpdateCommand); | ||
789 | } | ||
790 | |||
791 | private void HandleDataCommand(string module, string[] args) | ||
792 | { | ||
793 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene) | ||
794 | return; | ||
795 | |||
796 | if (args.Length != 7) | ||
797 | { | ||
798 | MainConsole.Instance.OutputFormat("Usage: debug lludp data out <true|false> <avatar-first-name> <avatar-last-name>"); | ||
799 | return; | ||
800 | } | ||
801 | |||
802 | int level; | ||
803 | if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out level)) | ||
804 | return; | ||
805 | |||
806 | string firstName = args[5]; | ||
807 | string lastName = args[6]; | ||
808 | |||
809 | Scene.ForEachScenePresence(sp => | ||
810 | { | ||
811 | if (sp.Firstname == firstName && sp.Lastname == lastName) | ||
812 | { | ||
813 | MainConsole.Instance.OutputFormat( | ||
814 | "Data debug for {0} ({1}) set to {2} in {3}", | ||
815 | sp.Name, sp.IsChildAgent ? "child" : "root", level, Scene.Name); | ||
816 | |||
817 | ((LLClientView)sp.ControllingClient).UDPClient.DebugDataOutLevel = level; | ||
818 | } | ||
819 | }); | ||
820 | } | 724 | } |
821 | 725 | ||
822 | private void HandleThrottleCommand(string module, string[] args) | 726 | public bool HandlesRegion(Location x) |
823 | { | ||
824 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene) | ||
825 | return; | ||
826 | |||
827 | if (args.Length != 7) | ||
828 | { | ||
829 | MainConsole.Instance.OutputFormat("Usage: debug lludp throttle log <level> <avatar-first-name> <avatar-last-name>"); | ||
830 | return; | ||
831 | } | ||
832 | |||
833 | int level; | ||
834 | if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out level)) | ||
835 | return; | ||
836 | |||
837 | string firstName = args[5]; | ||
838 | string lastName = args[6]; | ||
839 | |||
840 | Scene.ForEachScenePresence(sp => | ||
841 | { | ||
842 | if (sp.Firstname == firstName && sp.Lastname == lastName) | ||
843 | { | ||
844 | MainConsole.Instance.OutputFormat( | ||
845 | "Throttle log level for {0} ({1}) set to {2} in {3}", | ||
846 | sp.Name, sp.IsChildAgent ? "child" : "root", level, Scene.Name); | ||
847 | |||
848 | ((LLClientView)sp.ControllingClient).UDPClient.ThrottleDebugLevel = level; | ||
849 | } | ||
850 | }); | ||
851 | } | ||
852 | |||
853 | private void HandleThrottleStatusCommand(string module, string[] args) | ||
854 | { | ||
855 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene) | ||
856 | return; | ||
857 | |||
858 | if (args.Length != 6) | ||
859 | { | ||
860 | MainConsole.Instance.OutputFormat("Usage: debug lludp throttle status <avatar-first-name> <avatar-last-name>"); | ||
861 | return; | ||
862 | } | ||
863 | |||
864 | string firstName = args[4]; | ||
865 | string lastName = args[5]; | ||
866 | |||
867 | Scene.ForEachScenePresence(sp => | ||
868 | { | ||
869 | if (sp.Firstname == firstName && sp.Lastname == lastName) | ||
870 | { | ||
871 | MainConsole.Instance.OutputFormat( | ||
872 | "Status for {0} ({1}) in {2}", | ||
873 | sp.Name, sp.IsChildAgent ? "child" : "root", Scene.Name); | ||
874 | |||
875 | LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient; | ||
876 | MainConsole.Instance.OutputFormat("Adaptive throttle: {0}", udpClient.FlowThrottle.Enabled); | ||
877 | } | ||
878 | }); | ||
879 | } | ||
880 | |||
881 | private void HandlePacketCommand(string module, string[] args) | ||
882 | { | ||
883 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene) | ||
884 | return; | ||
885 | |||
886 | bool setAsDefaultLevel = false; | ||
887 | bool setAll = false; | ||
888 | OptionSet optionSet = new OptionSet() | ||
889 | .Add("default", o => setAsDefaultLevel = (o != null)) | ||
890 | .Add("all", o => setAll = (o != null)); | ||
891 | List<string> filteredArgs = optionSet.Parse(args); | ||
892 | |||
893 | string name = null; | ||
894 | |||
895 | if (filteredArgs.Count == 6) | ||
896 | { | ||
897 | if (!(setAsDefaultLevel || setAll)) | ||
898 | { | ||
899 | name = string.Format("{0} {1}", filteredArgs[4], filteredArgs[5]); | ||
900 | } | ||
901 | else | ||
902 | { | ||
903 | MainConsole.Instance.OutputFormat("ERROR: Cannot specify a user name when setting default/all logging level"); | ||
904 | return; | ||
905 | } | ||
906 | } | ||
907 | |||
908 | if (filteredArgs.Count > 3) | ||
909 | { | ||
910 | int newDebug; | ||
911 | if (int.TryParse(filteredArgs[3], out newDebug)) | ||
912 | { | ||
913 | if (setAsDefaultLevel || setAll) | ||
914 | { | ||
915 | DefaultClientPacketDebugLevel = newDebug; | ||
916 | |||
917 | MainConsole.Instance.OutputFormat( | ||
918 | "Packet debug for {0} clients set to {1} in {2}", | ||
919 | (setAll ? "all" : "future"), DefaultClientPacketDebugLevel, Scene.Name); | ||
920 | |||
921 | if (setAll) | ||
922 | { | ||
923 | Scene.ForEachScenePresence(sp => | ||
924 | { | ||
925 | MainConsole.Instance.OutputFormat( | ||
926 | "Packet debug for {0} ({1}) set to {2} in {3}", | ||
927 | sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, Scene.Name); | ||
928 | |||
929 | sp.ControllingClient.DebugPacketLevel = newDebug; | ||
930 | }); | ||
931 | } | ||
932 | } | ||
933 | else | ||
934 | { | ||
935 | Scene.ForEachScenePresence(sp => | ||
936 | { | ||
937 | if (name == null || sp.Name == name) | ||
938 | { | ||
939 | MainConsole.Instance.OutputFormat( | ||
940 | "Packet debug for {0} ({1}) set to {2} in {3}", | ||
941 | sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, Scene.Name); | ||
942 | |||
943 | sp.ControllingClient.DebugPacketLevel = newDebug; | ||
944 | } | ||
945 | }); | ||
946 | } | ||
947 | } | ||
948 | else | ||
949 | { | ||
950 | MainConsole.Instance.Output("Usage: debug lludp packet [--default | --all] 0..255 [<first-name> <last-name>]"); | ||
951 | } | ||
952 | } | ||
953 | } | ||
954 | |||
955 | private void HandleDropCommand(string module, string[] args) | ||
956 | { | ||
957 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene) | ||
958 | return; | ||
959 | |||
960 | if (args.Length != 6) | ||
961 | { | ||
962 | MainConsole.Instance.Output("Usage: debug lludp drop <in|out> <add|remove> <packet-name>"); | ||
963 | return; | ||
964 | } | ||
965 | |||
966 | string direction = args[3]; | ||
967 | string subCommand = args[4]; | ||
968 | string packetName = args[5]; | ||
969 | |||
970 | if (subCommand == "add") | ||
971 | { | ||
972 | MainConsole.Instance.OutputFormat( | ||
973 | "Adding packet {0} to {1} drop list for all connections in {2}", direction, packetName, Scene.Name); | ||
974 | |||
975 | Scene.ForEachScenePresence( | ||
976 | sp => | ||
977 | { | ||
978 | LLClientView llcv = (LLClientView)sp.ControllingClient; | ||
979 | |||
980 | if (direction == "in") | ||
981 | llcv.AddInPacketToDropSet(packetName); | ||
982 | else if (direction == "out") | ||
983 | llcv.AddOutPacketToDropSet(packetName); | ||
984 | } | ||
985 | ); | ||
986 | } | ||
987 | else if (subCommand == "remove") | ||
988 | { | ||
989 | MainConsole.Instance.OutputFormat( | ||
990 | "Removing packet {0} from {1} drop list for all connections in {2}", direction, packetName, Scene.Name); | ||
991 | |||
992 | Scene.ForEachScenePresence( | ||
993 | sp => | ||
994 | { | ||
995 | LLClientView llcv = (LLClientView)sp.ControllingClient; | ||
996 | |||
997 | if (direction == "in") | ||
998 | llcv.RemoveInPacketFromDropSet(packetName); | ||
999 | else if (direction == "out") | ||
1000 | llcv.RemoveOutPacketFromDropSet(packetName); | ||
1001 | } | ||
1002 | ); | ||
1003 | } | ||
1004 | } | ||
1005 | |||
1006 | private void HandleStartCommand(string module, string[] args) | ||
1007 | { | ||
1008 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene) | ||
1009 | return; | ||
1010 | |||
1011 | if (args.Length != 4) | ||
1012 | { | ||
1013 | MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>"); | ||
1014 | return; | ||
1015 | } | ||
1016 | |||
1017 | string subCommand = args[3]; | ||
1018 | |||
1019 | if (subCommand == "in" || subCommand == "all") | ||
1020 | StartInbound(); | ||
1021 | |||
1022 | if (subCommand == "out" || subCommand == "all") | ||
1023 | StartOutbound(); | ||
1024 | } | ||
1025 | |||
1026 | private void HandleStopCommand(string module, string[] args) | ||
1027 | { | 727 | { |
1028 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene) | 728 | return x == m_location; |
1029 | return; | ||
1030 | |||
1031 | if (args.Length != 4) | ||
1032 | { | ||
1033 | MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>"); | ||
1034 | return; | ||
1035 | } | ||
1036 | |||
1037 | string subCommand = args[3]; | ||
1038 | |||
1039 | if (subCommand == "in" || subCommand == "all") | ||
1040 | StopInbound(); | ||
1041 | |||
1042 | if (subCommand == "out" || subCommand == "all") | ||
1043 | StopOutbound(); | ||
1044 | } | 729 | } |
1045 | 730 | ||
1046 | private void HandlePoolCommand(string module, string[] args) | 731 | public int GetTotalQueuedOutgoingPackets() |
1047 | { | 732 | { |
1048 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene) | 733 | int total = 0; |
1049 | return; | ||
1050 | 734 | ||
1051 | if (args.Length != 4) | 735 | foreach (ScenePresence sp in Scene.GetScenePresences()) |
1052 | { | 736 | { |
1053 | MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); | 737 | LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient; |
1054 | return; | 738 | total += udpClient.GetTotalPacketsQueuedCount(); |
1055 | } | 739 | } |
1056 | 740 | ||
1057 | string enabled = args[3]; | 741 | return total; |
1058 | |||
1059 | if (enabled == "on") | ||
1060 | { | ||
1061 | if (EnablePools()) | ||
1062 | { | ||
1063 | EnablePoolStats(); | ||
1064 | MainConsole.Instance.OutputFormat("Packet pools enabled on {0}", Scene.Name); | ||
1065 | } | ||
1066 | } | ||
1067 | else if (enabled == "off") | ||
1068 | { | ||
1069 | if (DisablePools()) | ||
1070 | { | ||
1071 | DisablePoolStats(); | ||
1072 | MainConsole.Instance.OutputFormat("Packet pools disabled on {0}", Scene.Name); | ||
1073 | } | ||
1074 | } | ||
1075 | else | ||
1076 | { | ||
1077 | MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); | ||
1078 | } | ||
1079 | } | ||
1080 | |||
1081 | bool m_discardAgentUpdates; | ||
1082 | |||
1083 | private void HandleAgentUpdateCommand(string module, string[] args) | ||
1084 | { | ||
1085 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene) | ||
1086 | return; | ||
1087 | |||
1088 | m_discardAgentUpdates = !m_discardAgentUpdates; | ||
1089 | |||
1090 | MainConsole.Instance.OutputFormat( | ||
1091 | "Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, Scene.Name); | ||
1092 | } | ||
1093 | |||
1094 | private void HandleStatusCommand(string module, string[] args) | ||
1095 | { | ||
1096 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene) | ||
1097 | return; | ||
1098 | |||
1099 | MainConsole.Instance.OutputFormat( | ||
1100 | "IN LLUDP packet processing for {0} is {1}", Scene.Name, IsRunningInbound ? "enabled" : "disabled"); | ||
1101 | |||
1102 | MainConsole.Instance.OutputFormat( | ||
1103 | "OUT LLUDP packet processing for {0} is {1}", Scene.Name, IsRunningOutbound ? "enabled" : "disabled"); | ||
1104 | |||
1105 | MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", Scene.Name, UsePools ? "on" : "off"); | ||
1106 | |||
1107 | MainConsole.Instance.OutputFormat( | ||
1108 | "Packet debug level for new clients is {0}", DefaultClientPacketDebugLevel); | ||
1109 | } | ||
1110 | |||
1111 | public bool HandlesRegion(Location x) | ||
1112 | { | ||
1113 | return x == m_location; | ||
1114 | } | 742 | } |
1115 | 743 | ||
1116 | // public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) | 744 | // public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) |
@@ -1279,6 +907,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1279 | // packet so that it isn't sent before a queued update packet. | 907 | // packet so that it isn't sent before a queued update packet. |
1280 | bool forceQueue = (type == PacketType.KillObject); | 908 | bool forceQueue = (type == PacketType.KillObject); |
1281 | 909 | ||
910 | // if (type == PacketType.ImprovedTerseObjectUpdate) | ||
911 | // { | ||
912 | // m_log.DebugFormat("Direct send ITOU to {0} in {1}", udpClient.AgentID, Scene.Name); | ||
913 | // SendPacketFinal(outgoingPacket); | ||
914 | // return false; | ||
915 | // } | ||
916 | // else | ||
917 | // { | ||
1282 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, forceQueue)) | 918 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, forceQueue)) |
1283 | { | 919 | { |
1284 | SendPacketFinal(outgoingPacket); | 920 | SendPacketFinal(outgoingPacket); |
@@ -1288,6 +924,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1288 | { | 924 | { |
1289 | return false; | 925 | return false; |
1290 | } | 926 | } |
927 | // } | ||
1291 | 928 | ||
1292 | #endregion Queue or Send | 929 | #endregion Queue or Send |
1293 | } | 930 | } |
@@ -1363,7 +1000,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1363 | // Fire this out on a different thread so that we don't hold up outgoing packet processing for | 1000 | // Fire this out on a different thread so that we don't hold up outgoing packet processing for |
1364 | // everybody else if this is being called due to an ack timeout. | 1001 | // everybody else if this is being called due to an ack timeout. |
1365 | // This is the same as processing as the async process of a logout request. | 1002 | // This is the same as processing as the async process of a logout request. |
1366 | Util.FireAndForget(o => DeactivateClientDueToTimeout(client, timeoutTicks)); | 1003 | Util.FireAndForget( |
1004 | o => DeactivateClientDueToTimeout(client, timeoutTicks), null, "LLUDPServer.DeactivateClientDueToTimeout"); | ||
1367 | 1005 | ||
1368 | return; | 1006 | return; |
1369 | } | 1007 | } |
@@ -1597,7 +1235,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1597 | // buffer. | 1235 | // buffer. |
1598 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | 1236 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; |
1599 | 1237 | ||
1600 | Util.FireAndForget(HandleUseCircuitCode, array); | 1238 | Util.FireAndForget(HandleUseCircuitCode, array, "LLUDPServer.HandleUseCircuitCode"); |
1601 | 1239 | ||
1602 | return; | 1240 | return; |
1603 | } | 1241 | } |
@@ -1610,7 +1248,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1610 | // buffer. | 1248 | // buffer. |
1611 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; | 1249 | object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; |
1612 | 1250 | ||
1613 | Util.FireAndForget(HandleCompleteMovementIntoRegion, array); | 1251 | Util.FireAndForget( |
1252 | HandleCompleteMovementIntoRegion, array, "LLUDPServer.HandleCompleteMovementIntoRegion"); | ||
1614 | 1253 | ||
1615 | return; | 1254 | return; |
1616 | } | 1255 | } |
@@ -1732,7 +1371,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1732 | 1371 | ||
1733 | if (packet.Type == PacketType.AgentUpdate) | 1372 | if (packet.Type == PacketType.AgentUpdate) |
1734 | { | 1373 | { |
1735 | if (m_discardAgentUpdates) | 1374 | if (DiscardInboundAgentUpdates) |
1736 | return; | 1375 | return; |
1737 | 1376 | ||
1738 | ((LLClientView)client).TotalAgentUpdates++; | 1377 | ((LLClientView)client).TotalAgentUpdates++; |
@@ -2140,7 +1779,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2140 | { | 1779 | { |
2141 | if (!Scene.TryGetClient(agentID, out client)) | 1780 | if (!Scene.TryGetClient(agentID, out client)) |
2142 | { | 1781 | { |
2143 | LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); | 1782 | LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, Throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); |
2144 | 1783 | ||
2145 | client = new LLClientView(Scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); | 1784 | client = new LLClientView(Scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); |
2146 | client.OnLogout += LogoutHandler; | 1785 | client.OnLogout += LogoutHandler; |
@@ -2183,6 +1822,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2183 | 1822 | ||
2184 | private void IncomingPacketHandler() | 1823 | private void IncomingPacketHandler() |
2185 | { | 1824 | { |
1825 | Thread.CurrentThread.Priority = ThreadPriority.Highest; | ||
1826 | |||
2186 | // Set this culture for the thread that incoming packets are received | 1827 | // Set this culture for the thread that incoming packets are received |
2187 | // on to en-US to avoid number parsing issues | 1828 | // on to en-US to avoid number parsing issues |
2188 | Culture.SetCurrentCulture(); | 1829 | Culture.SetCurrentCulture(); |
@@ -2228,6 +1869,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2228 | 1869 | ||
2229 | private void OutgoingPacketHandler() | 1870 | private void OutgoingPacketHandler() |
2230 | { | 1871 | { |
1872 | Thread.CurrentThread.Priority = ThreadPriority.Highest; | ||
1873 | |||
2231 | // Set this culture for the thread that outgoing packets are sent | 1874 | // Set this culture for the thread that outgoing packets are sent |
2232 | // on to en-US to avoid number parsing issues | 1875 | // on to en-US to avoid number parsing issues |
2233 | Culture.SetCurrentCulture(); | 1876 | Culture.SetCurrentCulture(); |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs new file mode 100644 index 0000000..e0398d5 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs | |||
@@ -0,0 +1,762 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Text; | ||
31 | using NDesk.Options; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Framework.Console; | ||
34 | using OpenSim.Region.Framework.Scenes; | ||
35 | |||
36 | namespace OpenSim.Region.ClientStack.LindenUDP | ||
37 | { | ||
38 | public class LLUDPServerCommands | ||
39 | { | ||
40 | private ICommandConsole m_console; | ||
41 | private LLUDPServer m_udpServer; | ||
42 | |||
43 | public LLUDPServerCommands(ICommandConsole console, LLUDPServer udpServer) | ||
44 | { | ||
45 | m_console = console; | ||
46 | m_udpServer = udpServer; | ||
47 | } | ||
48 | |||
49 | public void Register() | ||
50 | { | ||
51 | m_console.Commands.AddCommand( | ||
52 | "Comms", false, "show server throttles", | ||
53 | "show server throttles", | ||
54 | "Show information about server throttles", | ||
55 | HandleShowServerThrottlesCommand); | ||
56 | |||
57 | m_console.Commands.AddCommand( | ||
58 | "Debug", false, "debug lludp packet", | ||
59 | "debug lludp packet [--default | --all] <level> [<avatar-first-name> <avatar-last-name>]", | ||
60 | "Turn on packet debugging. This logs information when the client stack hands a processed packet off to downstream code or when upstream code first requests that a certain packet be sent.", | ||
61 | "If level > 255 then all incoming and outgoing packets are logged.\n" | ||
62 | + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n" | ||
63 | + "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n" | ||
64 | + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n" | ||
65 | + "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n" | ||
66 | + "If level <= 0 then no packets are logged.\n" | ||
67 | + "If --default is specified then the level becomes the default logging level for all subsequent agents.\n" | ||
68 | + "If --all is specified then the level becomes the default logging level for all current and subsequent agents.\n" | ||
69 | + "In these cases, you cannot also specify an avatar name.\n" | ||
70 | + "If an avatar name is given then only packets from that avatar are logged.", | ||
71 | HandlePacketCommand); | ||
72 | |||
73 | m_console.Commands.AddCommand( | ||
74 | "Debug", false, "debug lludp data out", | ||
75 | "debug lludp data out <level> <avatar-first-name> <avatar-last-name>\"", | ||
76 | "Turn on debugging for final outgoing data to the given user's client.", | ||
77 | "This operates at a much lower level than the packet command and prints out available details when the data is actually sent.\n" | ||
78 | + "If level > 0 then information about all outgoing UDP data for this avatar is logged.\n" | ||
79 | + "If level <= 0 then no information about outgoing UDP data for this avatar is logged.", | ||
80 | HandleDataCommand); | ||
81 | |||
82 | m_console.Commands.AddCommand( | ||
83 | "Debug", false, "debug lludp drop", | ||
84 | "debug lludp drop <in|out> <add|remove> <packet-name>", | ||
85 | "Drop all in or outbound packets that match the given name", | ||
86 | "For test purposes.", | ||
87 | HandleDropCommand); | ||
88 | |||
89 | m_console.Commands.AddCommand( | ||
90 | "Debug", | ||
91 | false, | ||
92 | "debug lludp start", | ||
93 | "debug lludp start <in|out|all>", | ||
94 | "Control LLUDP packet processing.", | ||
95 | "No effect if packet processing has already started.\n" | ||
96 | + "in - start inbound processing.\n" | ||
97 | + "out - start outbound processing.\n" | ||
98 | + "all - start in and outbound processing.\n", | ||
99 | HandleStartCommand); | ||
100 | |||
101 | m_console.Commands.AddCommand( | ||
102 | "Debug", | ||
103 | false, | ||
104 | "debug lludp stop", | ||
105 | "debug lludp stop <in|out|all>", | ||
106 | "Stop LLUDP packet processing.", | ||
107 | "No effect if packet processing has already stopped.\n" | ||
108 | + "in - stop inbound processing.\n" | ||
109 | + "out - stop outbound processing.\n" | ||
110 | + "all - stop in and outbound processing.\n", | ||
111 | HandleStopCommand); | ||
112 | |||
113 | m_console.Commands.AddCommand( | ||
114 | "Debug", | ||
115 | false, | ||
116 | "debug lludp pool", | ||
117 | "debug lludp pool <on|off>", | ||
118 | "Turn object pooling within the lludp component on or off.", | ||
119 | HandlePoolCommand); | ||
120 | |||
121 | m_console.Commands.AddCommand( | ||
122 | "Debug", | ||
123 | false, | ||
124 | "debug lludp status", | ||
125 | "debug lludp status", | ||
126 | "Return status of LLUDP packet processing.", | ||
127 | HandleStatusCommand); | ||
128 | |||
129 | m_console.Commands.AddCommand( | ||
130 | "Debug", | ||
131 | false, | ||
132 | "debug lludp throttles log", | ||
133 | "debug lludp throttles log <level> [<avatar-first-name> <avatar-last-name>]", | ||
134 | "Change debug logging level for throttles.", | ||
135 | "If level >= 0 then throttle debug logging is performed.\n" | ||
136 | + "If level <= 0 then no throttle debug logging is performed.", | ||
137 | HandleThrottleCommand); | ||
138 | |||
139 | m_console.Commands.AddCommand( | ||
140 | "Debug", | ||
141 | false, | ||
142 | "debug lludp throttles get", | ||
143 | "debug lludp throttles get [<avatar-first-name> <avatar-last-name>]", | ||
144 | "Return debug settings for throttles.", | ||
145 | "adaptive - true/false, controls adaptive throttle setting.\n" | ||
146 | + "request - request drip rate in kbps.\n" | ||
147 | + "max - the max kbps throttle allowed for the specified existing clients. Use 'debug lludp get new-client-throttle-max' to see the setting for new clients.\n", | ||
148 | HandleThrottleGetCommand); | ||
149 | |||
150 | m_console.Commands.AddCommand( | ||
151 | "Debug", | ||
152 | false, | ||
153 | "debug lludp throttles set", | ||
154 | "debug lludp throttles set <param> <value> [<avatar-first-name> <avatar-last-name>]", | ||
155 | "Set a throttle parameter for the given client.", | ||
156 | "adaptive - true/false, controls adaptive throttle setting.\n" | ||
157 | + "current - current drip rate in kbps.\n" | ||
158 | + "request - requested drip rate in kbps.\n" | ||
159 | + "max - the max kbps throttle allowed for the specified existing clients. Use 'debug lludp set new-client-throttle-max' to change the settings for new clients.\n", | ||
160 | HandleThrottleSetCommand); | ||
161 | |||
162 | m_console.Commands.AddCommand( | ||
163 | "Debug", | ||
164 | false, | ||
165 | "debug lludp get", | ||
166 | "debug lludp get", | ||
167 | "Get debug parameters for the server.", | ||
168 | "max-scene-throttle - the current max cumulative kbps provided for this scene to clients.\n" | ||
169 | + "max-new-client-throttle - the max kbps throttle allowed to new clients. Use 'debug lludp throttles get max' to see the settings for existing clients.", | ||
170 | HandleGetCommand); | ||
171 | |||
172 | m_console.Commands.AddCommand( | ||
173 | "Debug", | ||
174 | false, | ||
175 | "debug lludp set", | ||
176 | "debug lludp set <param> <value>", | ||
177 | "Set a parameter for the server.", | ||
178 | "max-scene-throttle - the current max cumulative kbps provided for this scene to clients.\n" | ||
179 | + "max-new-client-throttle - the max kbps throttle allowed to each new client. Use 'debug lludp throttles set max' to set for existing clients.", | ||
180 | HandleSetCommand); | ||
181 | |||
182 | m_console.Commands.AddCommand( | ||
183 | "Debug", | ||
184 | false, | ||
185 | "debug lludp toggle agentupdate", | ||
186 | "debug lludp toggle agentupdate", | ||
187 | "Toggle whether agentupdate packets are processed or simply discarded.", | ||
188 | HandleAgentUpdateCommand); | ||
189 | } | ||
190 | |||
191 | private void HandleShowServerThrottlesCommand(string module, string[] args) | ||
192 | { | ||
193 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) | ||
194 | return; | ||
195 | |||
196 | m_console.OutputFormat("Throttles for {0}", m_udpServer.Scene.Name); | ||
197 | ConsoleDisplayList cdl = new ConsoleDisplayList(); | ||
198 | cdl.AddRow("Adaptive throttles", m_udpServer.ThrottleRates.AdaptiveThrottlesEnabled); | ||
199 | |||
200 | long maxSceneDripRate = m_udpServer.Throttle.MaxDripRate; | ||
201 | cdl.AddRow( | ||
202 | "Max scene throttle", | ||
203 | maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset"); | ||
204 | |||
205 | int maxClientDripRate = m_udpServer.ThrottleRates.Total; | ||
206 | cdl.AddRow( | ||
207 | "Max new client throttle", | ||
208 | maxClientDripRate != 0 ? string.Format("{0} kbps", maxClientDripRate * 8 / 1000) : "unset"); | ||
209 | |||
210 | m_console.Output(cdl.ToString()); | ||
211 | |||
212 | m_console.OutputFormat("{0}\n", GetServerThrottlesReport(m_udpServer)); | ||
213 | } | ||
214 | |||
215 | private string GetServerThrottlesReport(LLUDPServer udpServer) | ||
216 | { | ||
217 | StringBuilder report = new StringBuilder(); | ||
218 | |||
219 | report.AppendFormat( | ||
220 | "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}\n", | ||
221 | "Total", | ||
222 | "Resend", | ||
223 | "Land", | ||
224 | "Wind", | ||
225 | "Cloud", | ||
226 | "Task", | ||
227 | "Texture", | ||
228 | "Asset"); | ||
229 | |||
230 | report.AppendFormat( | ||
231 | "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}\n", | ||
232 | "kb/s", | ||
233 | "kb/s", | ||
234 | "kb/s", | ||
235 | "kb/s", | ||
236 | "kb/s", | ||
237 | "kb/s", | ||
238 | "kb/s", | ||
239 | "kb/s"); | ||
240 | |||
241 | ThrottleRates throttleRates = udpServer.ThrottleRates; | ||
242 | report.AppendFormat( | ||
243 | "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}", | ||
244 | (throttleRates.Total * 8) / 1000, | ||
245 | (throttleRates.Resend * 8) / 1000, | ||
246 | (throttleRates.Land * 8) / 1000, | ||
247 | (throttleRates.Wind * 8) / 1000, | ||
248 | (throttleRates.Cloud * 8) / 1000, | ||
249 | (throttleRates.Task * 8) / 1000, | ||
250 | (throttleRates.Texture * 8) / 1000, | ||
251 | (throttleRates.Asset * 8) / 1000); | ||
252 | |||
253 | return report.ToString(); | ||
254 | } | ||
255 | |||
256 | protected string GetColumnEntry(string entry, int maxLength, int columnPadding) | ||
257 | { | ||
258 | return string.Format( | ||
259 | "{0,-" + maxLength + "}{1,-" + columnPadding + "}", | ||
260 | entry.Length > maxLength ? entry.Substring(0, maxLength) : entry, | ||
261 | ""); | ||
262 | } | ||
263 | |||
264 | private void HandleDataCommand(string module, string[] args) | ||
265 | { | ||
266 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) | ||
267 | return; | ||
268 | |||
269 | if (args.Length != 7) | ||
270 | { | ||
271 | MainConsole.Instance.OutputFormat("Usage: debug lludp data out <true|false> <avatar-first-name> <avatar-last-name>"); | ||
272 | return; | ||
273 | } | ||
274 | |||
275 | int level; | ||
276 | if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out level)) | ||
277 | return; | ||
278 | |||
279 | string firstName = args[5]; | ||
280 | string lastName = args[6]; | ||
281 | |||
282 | m_udpServer.Scene.ForEachScenePresence(sp => | ||
283 | { | ||
284 | if (sp.Firstname == firstName && sp.Lastname == lastName) | ||
285 | { | ||
286 | MainConsole.Instance.OutputFormat( | ||
287 | "Data debug for {0} ({1}) set to {2} in {3}", | ||
288 | sp.Name, sp.IsChildAgent ? "child" : "root", level, m_udpServer.Scene.Name); | ||
289 | |||
290 | ((LLClientView)sp.ControllingClient).UDPClient.DebugDataOutLevel = level; | ||
291 | } | ||
292 | }); | ||
293 | } | ||
294 | |||
295 | private void HandleThrottleCommand(string module, string[] args) | ||
296 | { | ||
297 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) | ||
298 | return; | ||
299 | |||
300 | bool all = args.Length == 5; | ||
301 | bool one = args.Length == 7; | ||
302 | |||
303 | if (!all && !one) | ||
304 | { | ||
305 | MainConsole.Instance.OutputFormat( | ||
306 | "Usage: debug lludp throttles log <level> [<avatar-first-name> <avatar-last-name>]"); | ||
307 | return; | ||
308 | } | ||
309 | |||
310 | int level; | ||
311 | if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out level)) | ||
312 | return; | ||
313 | |||
314 | string firstName = null; | ||
315 | string lastName = null; | ||
316 | |||
317 | if (one) | ||
318 | { | ||
319 | firstName = args[5]; | ||
320 | lastName = args[6]; | ||
321 | } | ||
322 | |||
323 | m_udpServer.Scene.ForEachScenePresence(sp => | ||
324 | { | ||
325 | if (all || (sp.Firstname == firstName && sp.Lastname == lastName)) | ||
326 | { | ||
327 | MainConsole.Instance.OutputFormat( | ||
328 | "Throttle log level for {0} ({1}) set to {2} in {3}", | ||
329 | sp.Name, sp.IsChildAgent ? "child" : "root", level, m_udpServer.Scene.Name); | ||
330 | |||
331 | ((LLClientView)sp.ControllingClient).UDPClient.ThrottleDebugLevel = level; | ||
332 | } | ||
333 | }); | ||
334 | } | ||
335 | |||
336 | private void HandleThrottleSetCommand(string module, string[] args) | ||
337 | { | ||
338 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) | ||
339 | return; | ||
340 | |||
341 | bool all = args.Length == 6; | ||
342 | bool one = args.Length == 8; | ||
343 | |||
344 | if (!all && !one) | ||
345 | { | ||
346 | MainConsole.Instance.OutputFormat( | ||
347 | "Usage: debug lludp throttles set <param> <value> [<avatar-first-name> <avatar-last-name>]"); | ||
348 | return; | ||
349 | } | ||
350 | |||
351 | string param = args[4]; | ||
352 | string rawValue = args[5]; | ||
353 | |||
354 | string firstName = null; | ||
355 | string lastName = null; | ||
356 | |||
357 | if (one) | ||
358 | { | ||
359 | firstName = args[6]; | ||
360 | lastName = args[7]; | ||
361 | } | ||
362 | |||
363 | if (param == "adaptive") | ||
364 | { | ||
365 | bool newValue; | ||
366 | if (!ConsoleUtil.TryParseConsoleBool(MainConsole.Instance, rawValue, out newValue)) | ||
367 | return; | ||
368 | |||
369 | m_udpServer.Scene.ForEachScenePresence(sp => | ||
370 | { | ||
371 | if (all || (sp.Firstname == firstName && sp.Lastname == lastName)) | ||
372 | { | ||
373 | MainConsole.Instance.OutputFormat( | ||
374 | "Setting param {0} to {1} for {2} ({3}) in {4}", | ||
375 | param, newValue, sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name); | ||
376 | |||
377 | LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient; | ||
378 | udpClient.FlowThrottle.AdaptiveEnabled = newValue; | ||
379 | // udpClient.FlowThrottle.MaxDripRate = 0; | ||
380 | // udpClient.FlowThrottle.AdjustedDripRate = 0; | ||
381 | } | ||
382 | }); | ||
383 | } | ||
384 | else if (param == "request") | ||
385 | { | ||
386 | int newValue; | ||
387 | if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, rawValue, out newValue)) | ||
388 | return; | ||
389 | |||
390 | int newCurrentThrottleKbps = newValue * 1000 / 8; | ||
391 | |||
392 | m_udpServer.Scene.ForEachScenePresence(sp => | ||
393 | { | ||
394 | if (all || (sp.Firstname == firstName && sp.Lastname == lastName)) | ||
395 | { | ||
396 | MainConsole.Instance.OutputFormat( | ||
397 | "Setting param {0} to {1} for {2} ({3}) in {4}", | ||
398 | param, newValue, sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name); | ||
399 | |||
400 | LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient; | ||
401 | udpClient.FlowThrottle.RequestedDripRate = newCurrentThrottleKbps; | ||
402 | } | ||
403 | }); | ||
404 | } | ||
405 | else if (param == "max") | ||
406 | { | ||
407 | int newValue; | ||
408 | if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, rawValue, out newValue)) | ||
409 | return; | ||
410 | |||
411 | int newThrottleMaxKbps = newValue * 1000 / 8; | ||
412 | |||
413 | m_udpServer.Scene.ForEachScenePresence(sp => | ||
414 | { | ||
415 | if (all || (sp.Firstname == firstName && sp.Lastname == lastName)) | ||
416 | { | ||
417 | MainConsole.Instance.OutputFormat( | ||
418 | "Setting param {0} to {1} for {2} ({3}) in {4}", | ||
419 | param, newValue, sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name); | ||
420 | |||
421 | LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient; | ||
422 | udpClient.FlowThrottle.MaxDripRate = newThrottleMaxKbps; | ||
423 | } | ||
424 | }); | ||
425 | } | ||
426 | } | ||
427 | |||
428 | private void HandleThrottleGetCommand(string module, string[] args) | ||
429 | { | ||
430 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) | ||
431 | return; | ||
432 | |||
433 | bool all = args.Length == 4; | ||
434 | bool one = args.Length == 6; | ||
435 | |||
436 | if (!all && !one) | ||
437 | { | ||
438 | MainConsole.Instance.OutputFormat( | ||
439 | "Usage: debug lludp throttles get [<avatar-first-name> <avatar-last-name>]"); | ||
440 | return; | ||
441 | } | ||
442 | |||
443 | string firstName = null; | ||
444 | string lastName = null; | ||
445 | |||
446 | if (one) | ||
447 | { | ||
448 | firstName = args[4]; | ||
449 | lastName = args[5]; | ||
450 | } | ||
451 | |||
452 | m_udpServer.Scene.ForEachScenePresence(sp => | ||
453 | { | ||
454 | if (all || (sp.Firstname == firstName && sp.Lastname == lastName)) | ||
455 | { | ||
456 | m_console.OutputFormat( | ||
457 | "Status for {0} ({1}) in {2}", | ||
458 | sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name); | ||
459 | |||
460 | LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient; | ||
461 | |||
462 | ConsoleDisplayList cdl = new ConsoleDisplayList(); | ||
463 | cdl.AddRow("adaptive", udpClient.FlowThrottle.AdaptiveEnabled); | ||
464 | cdl.AddRow("current", string.Format("{0} kbps", udpClient.FlowThrottle.DripRate * 8 / 1000)); | ||
465 | cdl.AddRow("request", string.Format("{0} kbps", udpClient.FlowThrottle.RequestedDripRate * 8 / 1000)); | ||
466 | cdl.AddRow("max", string.Format("{0} kbps", udpClient.FlowThrottle.MaxDripRate * 8 / 1000)); | ||
467 | |||
468 | m_console.Output(cdl.ToString()); | ||
469 | } | ||
470 | }); | ||
471 | } | ||
472 | |||
473 | private void HandleGetCommand(string module, string[] args) | ||
474 | { | ||
475 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) | ||
476 | return; | ||
477 | |||
478 | m_console.OutputFormat("Debug settings for {0}", m_udpServer.Scene.Name); | ||
479 | ConsoleDisplayList cdl = new ConsoleDisplayList(); | ||
480 | |||
481 | long maxSceneDripRate = m_udpServer.Throttle.MaxDripRate; | ||
482 | cdl.AddRow( | ||
483 | "max-scene-throttle", | ||
484 | maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset"); | ||
485 | |||
486 | int maxClientDripRate = m_udpServer.ThrottleRates.Total; | ||
487 | cdl.AddRow( | ||
488 | "max-new-client-throttle", | ||
489 | maxClientDripRate != 0 ? string.Format("{0} kbps", maxClientDripRate * 8 / 1000) : "unset"); | ||
490 | |||
491 | m_console.Output(cdl.ToString()); | ||
492 | } | ||
493 | |||
494 | private void HandleSetCommand(string module, string[] args) | ||
495 | { | ||
496 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) | ||
497 | return; | ||
498 | |||
499 | if (args.Length != 5) | ||
500 | { | ||
501 | MainConsole.Instance.OutputFormat("Usage: debug lludp set <param> <value>"); | ||
502 | return; | ||
503 | } | ||
504 | |||
505 | string param = args[3]; | ||
506 | string rawValue = args[4]; | ||
507 | |||
508 | int newValue; | ||
509 | |||
510 | if (param == "max-scene-throttle") | ||
511 | { | ||
512 | if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, rawValue, out newValue)) | ||
513 | return; | ||
514 | |||
515 | m_udpServer.Throttle.MaxDripRate = newValue * 1000 / 8; | ||
516 | } | ||
517 | else if (param == "max-new-client-throttle") | ||
518 | { | ||
519 | if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, rawValue, out newValue)) | ||
520 | return; | ||
521 | |||
522 | m_udpServer.ThrottleRates.Total = newValue * 1000 / 8; | ||
523 | } | ||
524 | else | ||
525 | { | ||
526 | return; | ||
527 | } | ||
528 | |||
529 | m_console.OutputFormat("{0} set to {1} in {2}", param, rawValue, m_udpServer.Scene.Name); | ||
530 | } | ||
531 | |||
532 | private void HandlePacketCommand(string module, string[] args) | ||
533 | { | ||
534 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) | ||
535 | return; | ||
536 | |||
537 | bool setAsDefaultLevel = false; | ||
538 | bool setAll = false; | ||
539 | OptionSet optionSet = new OptionSet() | ||
540 | .Add("default", o => setAsDefaultLevel = (o != null)) | ||
541 | .Add("all", o => setAll = (o != null)); | ||
542 | List<string> filteredArgs = optionSet.Parse(args); | ||
543 | |||
544 | string name = null; | ||
545 | |||
546 | if (filteredArgs.Count == 6) | ||
547 | { | ||
548 | if (!(setAsDefaultLevel || setAll)) | ||
549 | { | ||
550 | name = string.Format("{0} {1}", filteredArgs[4], filteredArgs[5]); | ||
551 | } | ||
552 | else | ||
553 | { | ||
554 | MainConsole.Instance.OutputFormat("ERROR: Cannot specify a user name when setting default/all logging level"); | ||
555 | return; | ||
556 | } | ||
557 | } | ||
558 | |||
559 | if (filteredArgs.Count > 3) | ||
560 | { | ||
561 | int newDebug; | ||
562 | if (int.TryParse(filteredArgs[3], out newDebug)) | ||
563 | { | ||
564 | if (setAsDefaultLevel || setAll) | ||
565 | { | ||
566 | m_udpServer.DefaultClientPacketDebugLevel = newDebug; | ||
567 | |||
568 | MainConsole.Instance.OutputFormat( | ||
569 | "Packet debug for {0} clients set to {1} in {2}", | ||
570 | (setAll ? "all" : "future"), m_udpServer.DefaultClientPacketDebugLevel, m_udpServer.Scene.Name); | ||
571 | |||
572 | if (setAll) | ||
573 | { | ||
574 | m_udpServer.Scene.ForEachScenePresence(sp => | ||
575 | { | ||
576 | MainConsole.Instance.OutputFormat( | ||
577 | "Packet debug for {0} ({1}) set to {2} in {3}", | ||
578 | sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_udpServer.Scene.Name); | ||
579 | |||
580 | sp.ControllingClient.DebugPacketLevel = newDebug; | ||
581 | }); | ||
582 | } | ||
583 | } | ||
584 | else | ||
585 | { | ||
586 | m_udpServer.Scene.ForEachScenePresence(sp => | ||
587 | { | ||
588 | if (name == null || sp.Name == name) | ||
589 | { | ||
590 | MainConsole.Instance.OutputFormat( | ||
591 | "Packet debug for {0} ({1}) set to {2} in {3}", | ||
592 | sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_udpServer.Scene.Name); | ||
593 | |||
594 | sp.ControllingClient.DebugPacketLevel = newDebug; | ||
595 | } | ||
596 | }); | ||
597 | } | ||
598 | } | ||
599 | else | ||
600 | { | ||
601 | MainConsole.Instance.Output("Usage: debug lludp packet [--default | --all] 0..255 [<first-name> <last-name>]"); | ||
602 | } | ||
603 | } | ||
604 | } | ||
605 | |||
606 | private void HandleDropCommand(string module, string[] args) | ||
607 | { | ||
608 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) | ||
609 | return; | ||
610 | |||
611 | if (args.Length != 6) | ||
612 | { | ||
613 | MainConsole.Instance.Output("Usage: debug lludp drop <in|out> <add|remove> <packet-name>"); | ||
614 | return; | ||
615 | } | ||
616 | |||
617 | string direction = args[3]; | ||
618 | string subCommand = args[4]; | ||
619 | string packetName = args[5]; | ||
620 | |||
621 | if (subCommand == "add") | ||
622 | { | ||
623 | MainConsole.Instance.OutputFormat( | ||
624 | "Adding packet {0} to {1} drop list for all connections in {2}", | ||
625 | direction, packetName, m_udpServer.Scene.Name); | ||
626 | |||
627 | m_udpServer.Scene.ForEachScenePresence( | ||
628 | sp => | ||
629 | { | ||
630 | LLClientView llcv = (LLClientView)sp.ControllingClient; | ||
631 | |||
632 | if (direction == "in") | ||
633 | llcv.AddInPacketToDropSet(packetName); | ||
634 | else if (direction == "out") | ||
635 | llcv.AddOutPacketToDropSet(packetName); | ||
636 | } | ||
637 | ); | ||
638 | } | ||
639 | else if (subCommand == "remove") | ||
640 | { | ||
641 | MainConsole.Instance.OutputFormat( | ||
642 | "Removing packet {0} from {1} drop list for all connections in {2}", | ||
643 | direction, packetName, m_udpServer.Scene.Name); | ||
644 | |||
645 | m_udpServer.Scene.ForEachScenePresence( | ||
646 | sp => | ||
647 | { | ||
648 | LLClientView llcv = (LLClientView)sp.ControllingClient; | ||
649 | |||
650 | if (direction == "in") | ||
651 | llcv.RemoveInPacketFromDropSet(packetName); | ||
652 | else if (direction == "out") | ||
653 | llcv.RemoveOutPacketFromDropSet(packetName); | ||
654 | } | ||
655 | ); | ||
656 | } | ||
657 | } | ||
658 | |||
659 | private void HandleStartCommand(string module, string[] args) | ||
660 | { | ||
661 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) | ||
662 | return; | ||
663 | |||
664 | if (args.Length != 4) | ||
665 | { | ||
666 | MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>"); | ||
667 | return; | ||
668 | } | ||
669 | |||
670 | string subCommand = args[3]; | ||
671 | |||
672 | if (subCommand == "in" || subCommand == "all") | ||
673 | m_udpServer.StartInbound(); | ||
674 | |||
675 | if (subCommand == "out" || subCommand == "all") | ||
676 | m_udpServer.StartOutbound(); | ||
677 | } | ||
678 | |||
679 | private void HandleStopCommand(string module, string[] args) | ||
680 | { | ||
681 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) | ||
682 | return; | ||
683 | |||
684 | if (args.Length != 4) | ||
685 | { | ||
686 | MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>"); | ||
687 | return; | ||
688 | } | ||
689 | |||
690 | string subCommand = args[3]; | ||
691 | |||
692 | if (subCommand == "in" || subCommand == "all") | ||
693 | m_udpServer.StopInbound(); | ||
694 | |||
695 | if (subCommand == "out" || subCommand == "all") | ||
696 | m_udpServer.StopOutbound(); | ||
697 | } | ||
698 | |||
699 | private void HandlePoolCommand(string module, string[] args) | ||
700 | { | ||
701 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) | ||
702 | return; | ||
703 | |||
704 | if (args.Length != 4) | ||
705 | { | ||
706 | MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); | ||
707 | return; | ||
708 | } | ||
709 | |||
710 | string enabled = args[3]; | ||
711 | |||
712 | if (enabled == "on") | ||
713 | { | ||
714 | if (m_udpServer.EnablePools()) | ||
715 | { | ||
716 | m_udpServer.EnablePoolStats(); | ||
717 | MainConsole.Instance.OutputFormat("Packet pools enabled on {0}", m_udpServer.Scene.Name); | ||
718 | } | ||
719 | } | ||
720 | else if (enabled == "off") | ||
721 | { | ||
722 | if (m_udpServer.DisablePools()) | ||
723 | { | ||
724 | m_udpServer.DisablePoolStats(); | ||
725 | MainConsole.Instance.OutputFormat("Packet pools disabled on {0}", m_udpServer.Scene.Name); | ||
726 | } | ||
727 | } | ||
728 | else | ||
729 | { | ||
730 | MainConsole.Instance.Output("Usage: debug lludp pool <on|off>"); | ||
731 | } | ||
732 | } | ||
733 | |||
734 | private void HandleAgentUpdateCommand(string module, string[] args) | ||
735 | { | ||
736 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) | ||
737 | return; | ||
738 | |||
739 | m_udpServer.DiscardInboundAgentUpdates = !m_udpServer.DiscardInboundAgentUpdates; | ||
740 | |||
741 | MainConsole.Instance.OutputFormat( | ||
742 | "Discard AgentUpdates now {0} for {1}", m_udpServer.DiscardInboundAgentUpdates, m_udpServer.Scene.Name); | ||
743 | } | ||
744 | |||
745 | private void HandleStatusCommand(string module, string[] args) | ||
746 | { | ||
747 | if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) | ||
748 | return; | ||
749 | |||
750 | MainConsole.Instance.OutputFormat( | ||
751 | "IN LLUDP packet processing for {0} is {1}", m_udpServer.Scene.Name, m_udpServer.IsRunningInbound ? "enabled" : "disabled"); | ||
752 | |||
753 | MainConsole.Instance.OutputFormat( | ||
754 | "OUT LLUDP packet processing for {0} is {1}", m_udpServer.Scene.Name, m_udpServer.IsRunningOutbound ? "enabled" : "disabled"); | ||
755 | |||
756 | MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_udpServer.Scene.Name, m_udpServer.UsePools ? "on" : "off"); | ||
757 | |||
758 | MainConsole.Instance.OutputFormat( | ||
759 | "Packet debug level for new clients is {0}", m_udpServer.DefaultClientPacketDebugLevel); | ||
760 | } | ||
761 | } | ||
762 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index 88494be..94300f8 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs | |||
@@ -135,7 +135,7 @@ namespace OpenMetaverse | |||
135 | /// manner (not throwing an exception when the remote side resets the | 135 | /// manner (not throwing an exception when the remote side resets the |
136 | /// connection). This call is ignored on Mono where the flag is not | 136 | /// connection). This call is ignored on Mono where the flag is not |
137 | /// necessary</remarks> | 137 | /// necessary</remarks> |
138 | public void StartInbound(int recvBufferSize, bool asyncPacketHandling) | 138 | public virtual void StartInbound(int recvBufferSize, bool asyncPacketHandling) |
139 | { | 139 | { |
140 | m_asyncPacketHandling = asyncPacketHandling; | 140 | m_asyncPacketHandling = asyncPacketHandling; |
141 | 141 | ||
@@ -168,6 +168,12 @@ namespace OpenMetaverse | |||
168 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring"); | 168 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring"); |
169 | } | 169 | } |
170 | 170 | ||
171 | // On at least Mono 3.2.8, multiple UDP sockets can bind to the same port by default. At the moment | ||
172 | // we never want two regions to listen on the same port as they cannot demultiplex each other's messages, | ||
173 | // leading to a confusing bug. | ||
174 | // By default, Windows does not allow two sockets to bind to the same port. | ||
175 | m_udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); | ||
176 | |||
171 | if (recvBufferSize != 0) | 177 | if (recvBufferSize != 0) |
172 | m_udpSocket.ReceiveBufferSize = recvBufferSize; | 178 | m_udpSocket.ReceiveBufferSize = recvBufferSize; |
173 | 179 | ||
@@ -185,14 +191,14 @@ namespace OpenMetaverse | |||
185 | /// <summary> | 191 | /// <summary> |
186 | /// Start outbound UDP packet handling. | 192 | /// Start outbound UDP packet handling. |
187 | /// </summary> | 193 | /// </summary> |
188 | public void StartOutbound() | 194 | public virtual void StartOutbound() |
189 | { | 195 | { |
190 | m_log.DebugFormat("[UDPBASE]: Starting outbound UDP loop"); | 196 | m_log.DebugFormat("[UDPBASE]: Starting outbound UDP loop"); |
191 | 197 | ||
192 | IsRunningOutbound = true; | 198 | IsRunningOutbound = true; |
193 | } | 199 | } |
194 | 200 | ||
195 | public void StopInbound() | 201 | public virtual void StopInbound() |
196 | { | 202 | { |
197 | if (IsRunningInbound) | 203 | if (IsRunningInbound) |
198 | { | 204 | { |
@@ -203,14 +209,14 @@ namespace OpenMetaverse | |||
203 | } | 209 | } |
204 | } | 210 | } |
205 | 211 | ||
206 | public void StopOutbound() | 212 | public virtual void StopOutbound() |
207 | { | 213 | { |
208 | m_log.DebugFormat("[UDPBASE]: Stopping outbound UDP loop"); | 214 | m_log.DebugFormat("[UDPBASE]: Stopping outbound UDP loop"); |
209 | 215 | ||
210 | IsRunningOutbound = false; | 216 | IsRunningOutbound = false; |
211 | } | 217 | } |
212 | 218 | ||
213 | protected virtual bool EnablePools() | 219 | public virtual bool EnablePools() |
214 | { | 220 | { |
215 | if (!UsePools) | 221 | if (!UsePools) |
216 | { | 222 | { |
@@ -224,7 +230,7 @@ namespace OpenMetaverse | |||
224 | return false; | 230 | return false; |
225 | } | 231 | } |
226 | 232 | ||
227 | protected virtual bool DisablePools() | 233 | public virtual bool DisablePools() |
228 | { | 234 | { |
229 | if (UsePools) | 235 | if (UsePools) |
230 | { | 236 | { |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OutgoingQueueRefillEngine.cs b/OpenSim/Region/ClientStack/Linden/UDP/OutgoingQueueRefillEngine.cs index 069c9c8..1e915c3 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OutgoingQueueRefillEngine.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OutgoingQueueRefillEngine.cs | |||
@@ -124,7 +124,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
124 | 124 | ||
125 | StatsManager.RegisterStat(m_oqreRequestsWaitingStat); | 125 | StatsManager.RegisterStat(m_oqreRequestsWaitingStat); |
126 | 126 | ||
127 | Watchdog.StartThread( | 127 | WorkManager.StartThread( |
128 | ProcessRequests, | 128 | ProcessRequests, |
129 | String.Format("OutgoingQueueRefillEngineThread ({0})", m_udpServer.Scene.Name), | 129 | String.Format("OutgoingQueueRefillEngineThread ({0})", m_udpServer.Scene.Name), |
130 | ThreadPriority.Normal, | 130 | ThreadPriority.Normal, |
@@ -217,6 +217,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
217 | 217 | ||
218 | private void ProcessRequests() | 218 | private void ProcessRequests() |
219 | { | 219 | { |
220 | Thread.CurrentThread.Priority = ThreadPriority.Highest; | ||
221 | |||
220 | try | 222 | try |
221 | { | 223 | { |
222 | while (IsRunning || m_requestQueue.Count > 0) | 224 | while (IsRunning || m_requestQueue.Count > 0) |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs index e9aeffe..a935dd2 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs | |||
@@ -36,7 +36,6 @@ using OpenSim.Framework; | |||
36 | using OpenSim.Framework.Monitoring; | 36 | using OpenSim.Framework.Monitoring; |
37 | using OpenSim.Region.Framework.Scenes; | 37 | using OpenSim.Region.Framework.Scenes; |
38 | using OpenSim.Tests.Common; | 38 | using OpenSim.Tests.Common; |
39 | using OpenSim.Tests.Common.Mock; | ||
40 | 39 | ||
41 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests | 40 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests |
42 | { | 41 | { |
@@ -47,7 +46,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
47 | public class BasicCircuitTests : OpenSimTestCase | 46 | public class BasicCircuitTests : OpenSimTestCase |
48 | { | 47 | { |
49 | private Scene m_scene; | 48 | private Scene m_scene; |
50 | private TestLLUDPServer m_udpServer; | ||
51 | 49 | ||
52 | [TestFixtureSetUp] | 50 | [TestFixtureSetUp] |
53 | public void FixtureInit() | 51 | public void FixtureInit() |
@@ -73,72 +71,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
73 | StatsManager.SimExtraStats = new SimExtraStatsCollector(); | 71 | StatsManager.SimExtraStats = new SimExtraStatsCollector(); |
74 | } | 72 | } |
75 | 73 | ||
76 | /// <summary> | 74 | // /// <summary> |
77 | /// Build an object name packet for test purposes | 75 | // /// Build an object name packet for test purposes |
78 | /// </summary> | 76 | // /// </summary> |
79 | /// <param name="objectLocalId"></param> | 77 | // /// <param name="objectLocalId"></param> |
80 | /// <param name="objectName"></param> | 78 | // /// <param name="objectName"></param> |
81 | private ObjectNamePacket BuildTestObjectNamePacket(uint objectLocalId, string objectName) | 79 | // private ObjectNamePacket BuildTestObjectNamePacket(uint objectLocalId, string objectName) |
82 | { | 80 | // { |
83 | ObjectNamePacket onp = new ObjectNamePacket(); | 81 | // ObjectNamePacket onp = new ObjectNamePacket(); |
84 | ObjectNamePacket.ObjectDataBlock odb = new ObjectNamePacket.ObjectDataBlock(); | 82 | // ObjectNamePacket.ObjectDataBlock odb = new ObjectNamePacket.ObjectDataBlock(); |
85 | odb.LocalID = objectLocalId; | 83 | // odb.LocalID = objectLocalId; |
86 | odb.Name = Utils.StringToBytes(objectName); | 84 | // odb.Name = Utils.StringToBytes(objectName); |
87 | onp.ObjectData = new ObjectNamePacket.ObjectDataBlock[] { odb }; | 85 | // onp.ObjectData = new ObjectNamePacket.ObjectDataBlock[] { odb }; |
88 | onp.Header.Zerocoded = false; | 86 | // onp.Header.Zerocoded = false; |
89 | 87 | // | |
90 | return onp; | 88 | // return onp; |
91 | } | 89 | // } |
92 | 90 | // | |
93 | private void AddUdpServer() | ||
94 | { | ||
95 | AddUdpServer(new IniConfigSource()); | ||
96 | } | ||
97 | |||
98 | private void AddUdpServer(IniConfigSource configSource) | ||
99 | { | ||
100 | uint port = 0; | ||
101 | AgentCircuitManager acm = m_scene.AuthenticateHandler; | ||
102 | |||
103 | m_udpServer = new TestLLUDPServer(IPAddress.Any, ref port, 0, false, configSource, acm); | ||
104 | m_udpServer.AddScene(m_scene); | ||
105 | } | ||
106 | |||
107 | /// <summary> | ||
108 | /// Used by tests that aren't testing this stage. | ||
109 | /// </summary> | ||
110 | private ScenePresence AddClient() | ||
111 | { | ||
112 | UUID myAgentUuid = TestHelpers.ParseTail(0x1); | ||
113 | UUID mySessionUuid = TestHelpers.ParseTail(0x2); | ||
114 | uint myCircuitCode = 123456; | ||
115 | IPEndPoint testEp = new IPEndPoint(IPAddress.Loopback, 999); | ||
116 | |||
117 | UseCircuitCodePacket uccp = new UseCircuitCodePacket(); | ||
118 | |||
119 | UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock | ||
120 | = new UseCircuitCodePacket.CircuitCodeBlock(); | ||
121 | uccpCcBlock.Code = myCircuitCode; | ||
122 | uccpCcBlock.ID = myAgentUuid; | ||
123 | uccpCcBlock.SessionID = mySessionUuid; | ||
124 | uccp.CircuitCode = uccpCcBlock; | ||
125 | |||
126 | byte[] uccpBytes = uccp.ToBytes(); | ||
127 | UDPPacketBuffer upb = new UDPPacketBuffer(testEp, uccpBytes.Length); | ||
128 | upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor. | ||
129 | Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length); | ||
130 | |||
131 | AgentCircuitData acd = new AgentCircuitData(); | ||
132 | acd.AgentID = myAgentUuid; | ||
133 | acd.SessionID = mySessionUuid; | ||
134 | |||
135 | m_scene.AuthenticateHandler.AddNewCircuit(myCircuitCode, acd); | ||
136 | |||
137 | m_udpServer.PacketReceived(upb); | ||
138 | |||
139 | return m_scene.GetScenePresence(myAgentUuid); | ||
140 | } | ||
141 | |||
142 | /// <summary> | 91 | /// <summary> |
143 | /// Test adding a client to the stack | 92 | /// Test adding a client to the stack |
144 | /// </summary> | 93 | /// </summary> |
@@ -148,7 +97,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
148 | TestHelpers.InMethod(); | 97 | TestHelpers.InMethod(); |
149 | // TestHelpers.EnableLogging(); | 98 | // TestHelpers.EnableLogging(); |
150 | 99 | ||
151 | AddUdpServer(); | 100 | TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(m_scene); |
152 | 101 | ||
153 | UUID myAgentUuid = TestHelpers.ParseTail(0x1); | 102 | UUID myAgentUuid = TestHelpers.ParseTail(0x1); |
154 | UUID mySessionUuid = TestHelpers.ParseTail(0x2); | 103 | UUID mySessionUuid = TestHelpers.ParseTail(0x2); |
@@ -169,7 +118,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
169 | upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor. | 118 | upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor. |
170 | Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length); | 119 | Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length); |
171 | 120 | ||
172 | m_udpServer.PacketReceived(upb); | 121 | udpServer.PacketReceived(upb); |
173 | 122 | ||
174 | // Presence shouldn't exist since the circuit manager doesn't know about this circuit for authentication yet | 123 | // Presence shouldn't exist since the circuit manager doesn't know about this circuit for authentication yet |
175 | Assert.That(m_scene.GetScenePresence(myAgentUuid), Is.Null); | 124 | Assert.That(m_scene.GetScenePresence(myAgentUuid), Is.Null); |
@@ -180,15 +129,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
180 | 129 | ||
181 | m_scene.AuthenticateHandler.AddNewCircuit(myCircuitCode, acd); | 130 | m_scene.AuthenticateHandler.AddNewCircuit(myCircuitCode, acd); |
182 | 131 | ||
183 | m_udpServer.PacketReceived(upb); | 132 | udpServer.PacketReceived(upb); |
184 | 133 | ||
185 | // Should succeed now | 134 | // Should succeed now |
186 | ScenePresence sp = m_scene.GetScenePresence(myAgentUuid); | 135 | ScenePresence sp = m_scene.GetScenePresence(myAgentUuid); |
187 | Assert.That(sp.UUID, Is.EqualTo(myAgentUuid)); | 136 | Assert.That(sp.UUID, Is.EqualTo(myAgentUuid)); |
188 | 137 | ||
189 | Assert.That(m_udpServer.PacketsSent.Count, Is.EqualTo(1)); | 138 | Assert.That(udpServer.PacketsSent.Count, Is.EqualTo(1)); |
190 | 139 | ||
191 | Packet packet = m_udpServer.PacketsSent[0]; | 140 | Packet packet = udpServer.PacketsSent[0]; |
192 | Assert.That(packet, Is.InstanceOf(typeof(PacketAckPacket))); | 141 | Assert.That(packet, Is.InstanceOf(typeof(PacketAckPacket))); |
193 | 142 | ||
194 | PacketAckPacket ackPacket = packet as PacketAckPacket; | 143 | PacketAckPacket ackPacket = packet as PacketAckPacket; |
@@ -200,15 +149,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
200 | public void TestLogoutClientDueToAck() | 149 | public void TestLogoutClientDueToAck() |
201 | { | 150 | { |
202 | TestHelpers.InMethod(); | 151 | TestHelpers.InMethod(); |
203 | TestHelpers.EnableLogging(); | 152 | // TestHelpers.EnableLogging(); |
204 | 153 | ||
205 | IniConfigSource ics = new IniConfigSource(); | 154 | IniConfigSource ics = new IniConfigSource(); |
206 | IConfig config = ics.AddConfig("ClientStack.LindenUDP"); | 155 | IConfig config = ics.AddConfig("ClientStack.LindenUDP"); |
207 | config.Set("AckTimeout", -1); | 156 | config.Set("AckTimeout", -1); |
208 | AddUdpServer(ics); | 157 | TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(m_scene, ics); |
158 | |||
159 | ScenePresence sp | ||
160 | = ClientStackHelpers.AddChildClient( | ||
161 | m_scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); | ||
209 | 162 | ||
210 | ScenePresence sp = AddClient(); | 163 | udpServer.ClientOutgoingPacketHandler(sp.ControllingClient, true, false, false); |
211 | m_udpServer.ClientOutgoingPacketHandler(sp.ControllingClient, true, false, false); | ||
212 | 164 | ||
213 | ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID); | 165 | ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID); |
214 | Assert.That(spAfterAckTimeout, Is.Null); | 166 | Assert.That(spAfterAckTimeout, Is.Null); |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs index 575e54c..6c57e6d 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs | |||
@@ -39,7 +39,6 @@ using OpenSim.Framework; | |||
39 | using OpenSim.Region.CoreModules.Agent.TextureSender; | 39 | using OpenSim.Region.CoreModules.Agent.TextureSender; |
40 | using OpenSim.Region.Framework.Scenes; | 40 | using OpenSim.Region.Framework.Scenes; |
41 | using OpenSim.Tests.Common; | 41 | using OpenSim.Tests.Common; |
42 | using OpenSim.Tests.Common.Mock; | ||
43 | 42 | ||
44 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests | 43 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests |
45 | { | 44 | { |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs deleted file mode 100644 index 39d1875..0000000 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs +++ /dev/null | |||
@@ -1,79 +0,0 @@ | |||
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 | |||
28 | using System.Net; | ||
29 | using OpenMetaverse; | ||
30 | using OpenSim.Framework; | ||
31 | using OpenSim.Region.Framework.Scenes; | ||
32 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
33 | |||
34 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests | ||
35 | { | ||
36 | /// <summary> | ||
37 | /// Mock scene for unit tests | ||
38 | /// </summary> | ||
39 | public class MockScene : SceneBase | ||
40 | { | ||
41 | public int ObjectNameCallsReceived | ||
42 | { | ||
43 | get { return m_objectNameCallsReceived; } | ||
44 | } | ||
45 | protected int m_objectNameCallsReceived; | ||
46 | |||
47 | public MockScene() : base(new RegionInfo(1000, 1000, null, null)) | ||
48 | { | ||
49 | m_regStatus = RegionStatus.Up; | ||
50 | } | ||
51 | |||
52 | public override bool Update(int frames) { return true; } | ||
53 | public override void LoadWorldMap() {} | ||
54 | |||
55 | public override ISceneAgent AddNewAgent(IClientAPI client, PresenceType type) | ||
56 | { | ||
57 | client.OnObjectName += RecordObjectNameCall; | ||
58 | |||
59 | // FIXME | ||
60 | return null; | ||
61 | } | ||
62 | |||
63 | public override bool CloseAgent(UUID agentID, bool force) { return true; } | ||
64 | |||
65 | public override bool CheckClient(UUID clientId, IPEndPoint endPoint) { return true; } | ||
66 | |||
67 | public override void OtherRegionUp(GridRegion otherRegion) { } | ||
68 | |||
69 | public override bool TryGetScenePresence(UUID uuid, out ScenePresence sp) { sp = null; return false; } | ||
70 | |||
71 | /// <summary> | ||
72 | /// Doesn't really matter what the call is - we're using this to test that a packet has actually been received | ||
73 | /// </summary> | ||
74 | protected void RecordObjectNameCall(IClientAPI remoteClient, uint localID, string message) | ||
75 | { | ||
76 | m_objectNameCallsReceived++; | ||
77 | } | ||
78 | } | ||
79 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs index 5f73a94..92f1fc3 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs | |||
@@ -30,7 +30,6 @@ using NUnit.Framework; | |||
30 | using OpenMetaverse; | 30 | using OpenMetaverse; |
31 | using OpenMetaverse.Packets; | 31 | using OpenMetaverse.Packets; |
32 | using OpenSim.Framework; | 32 | using OpenSim.Framework; |
33 | using OpenSim.Tests.Common.Mock; | ||
34 | using OpenSim.Tests.Common; | 33 | using OpenSim.Tests.Common; |
35 | 34 | ||
36 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests | 35 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs deleted file mode 100644 index 27b9e5b..0000000 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs +++ /dev/null | |||
@@ -1,170 +0,0 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Net; | ||
31 | using System.Net.Sockets; | ||
32 | using Nini.Config; | ||
33 | using OpenMetaverse.Packets; | ||
34 | using OpenSim.Framework; | ||
35 | |||
36 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests | ||
37 | { | ||
38 | /// <summary> | ||
39 | /// This class enables regression testing of the LLUDPServer by allowing us to intercept outgoing data. | ||
40 | /// </summary> | ||
41 | public class TestLLUDPServer : LLUDPServer | ||
42 | { | ||
43 | public List<Packet> PacketsSent { get; private set; } | ||
44 | |||
45 | public TestLLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) | ||
46 | : base(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager) | ||
47 | { | ||
48 | PacketsSent = new List<Packet>(); | ||
49 | } | ||
50 | |||
51 | public override void SendAckImmediate(IPEndPoint remoteEndpoint, PacketAckPacket ack) | ||
52 | { | ||
53 | PacketsSent.Add(ack); | ||
54 | } | ||
55 | |||
56 | public override void SendPacket( | ||
57 | LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting, UnackedPacketMethod method) | ||
58 | { | ||
59 | PacketsSent.Add(packet); | ||
60 | } | ||
61 | |||
62 | public void ClientOutgoingPacketHandler(IClientAPI client, bool resendUnacked, bool sendAcks, bool sendPing) | ||
63 | { | ||
64 | m_resendUnacked = resendUnacked; | ||
65 | m_sendAcks = sendAcks; | ||
66 | m_sendPing = sendPing; | ||
67 | |||
68 | ClientOutgoingPacketHandler(client); | ||
69 | } | ||
70 | |||
71 | //// /// <summary> | ||
72 | //// /// The chunks of data to pass to the LLUDPServer when it calls EndReceive | ||
73 | //// /// </summary> | ||
74 | //// protected Queue<ChunkSenderTuple> m_chunksToLoad = new Queue<ChunkSenderTuple>(); | ||
75 | // | ||
76 | //// protected override void BeginReceive() | ||
77 | //// { | ||
78 | //// if (m_chunksToLoad.Count > 0 && m_chunksToLoad.Peek().BeginReceiveException) | ||
79 | //// { | ||
80 | //// ChunkSenderTuple tuple = m_chunksToLoad.Dequeue(); | ||
81 | //// reusedEpSender = tuple.Sender; | ||
82 | //// throw new SocketException(); | ||
83 | //// } | ||
84 | //// } | ||
85 | // | ||
86 | //// protected override bool EndReceive(out int numBytes, IAsyncResult result, ref EndPoint epSender) | ||
87 | //// { | ||
88 | //// numBytes = 0; | ||
89 | //// | ||
90 | //// //m_log.Debug("Queue size " + m_chunksToLoad.Count); | ||
91 | //// | ||
92 | //// if (m_chunksToLoad.Count <= 0) | ||
93 | //// return false; | ||
94 | //// | ||
95 | //// ChunkSenderTuple tuple = m_chunksToLoad.Dequeue(); | ||
96 | //// RecvBuffer = tuple.Data; | ||
97 | //// numBytes = tuple.Data.Length; | ||
98 | //// epSender = tuple.Sender; | ||
99 | //// | ||
100 | //// return true; | ||
101 | //// } | ||
102 | // | ||
103 | //// public override void SendPacketTo(byte[] buffer, int size, SocketFlags flags, uint circuitcode) | ||
104 | //// { | ||
105 | //// // Don't do anything just yet | ||
106 | //// } | ||
107 | // | ||
108 | // /// <summary> | ||
109 | // /// Signal that this chunk should throw an exception on Socket.BeginReceive() | ||
110 | // /// </summary> | ||
111 | // /// <param name="epSender"></param> | ||
112 | // public void LoadReceiveWithBeginException(EndPoint epSender) | ||
113 | // { | ||
114 | // ChunkSenderTuple tuple = new ChunkSenderTuple(epSender); | ||
115 | // tuple.BeginReceiveException = true; | ||
116 | // m_chunksToLoad.Enqueue(tuple); | ||
117 | // } | ||
118 | // | ||
119 | // /// <summary> | ||
120 | // /// Load some data to be received by the LLUDPServer on the next receive call | ||
121 | // /// </summary> | ||
122 | // /// <param name="data"></param> | ||
123 | // /// <param name="epSender"></param> | ||
124 | // public void LoadReceive(byte[] data, EndPoint epSender) | ||
125 | // { | ||
126 | // m_chunksToLoad.Enqueue(new ChunkSenderTuple(data, epSender)); | ||
127 | // } | ||
128 | // | ||
129 | // /// <summary> | ||
130 | // /// Load a packet to be received by the LLUDPServer on the next receive call | ||
131 | // /// </summary> | ||
132 | // /// <param name="packet"></param> | ||
133 | // public void LoadReceive(Packet packet, EndPoint epSender) | ||
134 | // { | ||
135 | // LoadReceive(packet.ToBytes(), epSender); | ||
136 | // } | ||
137 | // | ||
138 | // /// <summary> | ||
139 | // /// Calls the protected asynchronous result method. This fires out all data chunks currently queued for send | ||
140 | // /// </summary> | ||
141 | // /// <param name="result"></param> | ||
142 | // public void ReceiveData(IAsyncResult result) | ||
143 | // { | ||
144 | // // Doesn't work the same way anymore | ||
145 | //// while (m_chunksToLoad.Count > 0) | ||
146 | //// OnReceivedData(result); | ||
147 | // } | ||
148 | } | ||
149 | |||
150 | /// <summary> | ||
151 | /// Record the data and sender tuple | ||
152 | /// </summary> | ||
153 | public class ChunkSenderTuple | ||
154 | { | ||
155 | public byte[] Data; | ||
156 | public EndPoint Sender; | ||
157 | public bool BeginReceiveException; | ||
158 | |||
159 | public ChunkSenderTuple(byte[] data, EndPoint sender) | ||
160 | { | ||
161 | Data = data; | ||
162 | Sender = sender; | ||
163 | } | ||
164 | |||
165 | public ChunkSenderTuple(EndPoint sender) | ||
166 | { | ||
167 | Sender = sender; | ||
168 | } | ||
169 | } | ||
170 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs new file mode 100644 index 0000000..0560b9b --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs | |||
@@ -0,0 +1,425 @@ | |||
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 | |||
28 | using System; | ||
29 | using Nini.Config; | ||
30 | using NUnit.Framework; | ||
31 | using OpenMetaverse.Packets; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.Framework.Scenes; | ||
34 | using OpenSim.Tests.Common; | ||
35 | |||
36 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests | ||
37 | { | ||
38 | [TestFixture] | ||
39 | public class ThrottleTests : OpenSimTestCase | ||
40 | { | ||
41 | [TestFixtureSetUp] | ||
42 | public void FixtureInit() | ||
43 | { | ||
44 | // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. | ||
45 | Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; | ||
46 | } | ||
47 | |||
48 | [TestFixtureTearDown] | ||
49 | public void TearDown() | ||
50 | { | ||
51 | // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple | ||
52 | // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression | ||
53 | // tests really shouldn't). | ||
54 | Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; | ||
55 | } | ||
56 | |||
57 | [Test] | ||
58 | public void TestSetRequestDripRate() | ||
59 | { | ||
60 | TestHelpers.InMethod(); | ||
61 | |||
62 | TokenBucket tb = new TokenBucket("tb", null, 5000, 0); | ||
63 | AssertRates(tb, 5000, 0, 5000, 0); | ||
64 | |||
65 | tb.RequestedDripRate = 4000; | ||
66 | AssertRates(tb, 4000, 0, 4000, 0); | ||
67 | |||
68 | tb.RequestedDripRate = 6000; | ||
69 | AssertRates(tb, 6000, 0, 6000, 0); | ||
70 | } | ||
71 | |||
72 | [Test] | ||
73 | public void TestSetRequestDripRateWithMax() | ||
74 | { | ||
75 | TestHelpers.InMethod(); | ||
76 | |||
77 | TokenBucket tb = new TokenBucket("tb", null, 5000, 10000); | ||
78 | AssertRates(tb, 5000, 0, 5000, 10000); | ||
79 | |||
80 | tb.RequestedDripRate = 4000; | ||
81 | AssertRates(tb, 4000, 0, 4000, 10000); | ||
82 | |||
83 | tb.RequestedDripRate = 6000; | ||
84 | AssertRates(tb, 6000, 0, 6000, 10000); | ||
85 | |||
86 | tb.RequestedDripRate = 12000; | ||
87 | AssertRates(tb, 10000, 0, 10000, 10000); | ||
88 | } | ||
89 | |||
90 | [Test] | ||
91 | public void TestSetRequestDripRateWithChildren() | ||
92 | { | ||
93 | TestHelpers.InMethod(); | ||
94 | |||
95 | TokenBucket tbParent = new TokenBucket("tbParent", null, 0, 0); | ||
96 | TokenBucket tbChild1 = new TokenBucket("tbChild1", tbParent, 3000, 0); | ||
97 | TokenBucket tbChild2 = new TokenBucket("tbChild2", tbParent, 5000, 0); | ||
98 | |||
99 | AssertRates(tbParent, 8000, 8000, 8000, 0); | ||
100 | AssertRates(tbChild1, 3000, 0, 3000, 0); | ||
101 | AssertRates(tbChild2, 5000, 0, 5000, 0); | ||
102 | |||
103 | // Test: Setting a parent request greater than total children requests. | ||
104 | tbParent.RequestedDripRate = 10000; | ||
105 | |||
106 | AssertRates(tbParent, 10000, 8000, 8000, 0); | ||
107 | AssertRates(tbChild1, 3000, 0, 3000, 0); | ||
108 | AssertRates(tbChild2, 5000, 0, 5000, 0); | ||
109 | |||
110 | // Test: Setting a parent request lower than total children requests. | ||
111 | tbParent.RequestedDripRate = 6000; | ||
112 | |||
113 | AssertRates(tbParent, 6000, 8000, 6000, 0); | ||
114 | AssertRates(tbChild1, 3000, 0, 6000 / 8 * 3, 0); | ||
115 | AssertRates(tbChild2, 5000, 0, 6000 / 8 * 5, 0); | ||
116 | } | ||
117 | |||
118 | private void AssertRates( | ||
119 | TokenBucket tb, double requestedDripRate, double totalDripRequest, double dripRate, double maxDripRate) | ||
120 | { | ||
121 | Assert.AreEqual((int)requestedDripRate, tb.RequestedDripRate, "Requested drip rate"); | ||
122 | Assert.AreEqual((int)totalDripRequest, tb.TotalDripRequest, "Total drip request"); | ||
123 | Assert.AreEqual((int)dripRate, tb.DripRate, "Drip rate"); | ||
124 | Assert.AreEqual((int)maxDripRate, tb.MaxDripRate, "Max drip rate"); | ||
125 | } | ||
126 | |||
127 | [Test] | ||
128 | public void TestClientThrottleSetNoLimit() | ||
129 | { | ||
130 | TestHelpers.InMethod(); | ||
131 | // TestHelpers.EnableLogging(); | ||
132 | |||
133 | Scene scene = new SceneHelpers().SetupScene(); | ||
134 | TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene); | ||
135 | |||
136 | ScenePresence sp | ||
137 | = ClientStackHelpers.AddChildClient( | ||
138 | scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); | ||
139 | |||
140 | LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient; | ||
141 | |||
142 | udpServer.Throttle.DebugLevel = 1; | ||
143 | udpClient.ThrottleDebugLevel = 1; | ||
144 | |||
145 | int resendBytes = 1000; | ||
146 | int landBytes = 2000; | ||
147 | int windBytes = 3000; | ||
148 | int cloudBytes = 4000; | ||
149 | int taskBytes = 5000; | ||
150 | int textureBytes = 6000; | ||
151 | int assetBytes = 7000; | ||
152 | |||
153 | SetThrottles( | ||
154 | udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); | ||
155 | |||
156 | // We expect this to be lower because of the minimum bound set by MTU | ||
157 | int totalBytes = LLUDPServer.MTU + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes; | ||
158 | |||
159 | AssertThrottles( | ||
160 | udpClient, | ||
161 | LLUDPServer.MTU, landBytes, windBytes, cloudBytes, taskBytes, | ||
162 | textureBytes, assetBytes, totalBytes, 0, 0); | ||
163 | } | ||
164 | |||
165 | [Test] | ||
166 | public void TestClientThrottleAdaptiveNoLimit() | ||
167 | { | ||
168 | TestHelpers.InMethod(); | ||
169 | // TestHelpers.EnableLogging(); | ||
170 | |||
171 | Scene scene = new SceneHelpers().SetupScene(); | ||
172 | |||
173 | IniConfigSource ics = new IniConfigSource(); | ||
174 | IConfig config = ics.AddConfig("ClientStack.LindenUDP"); | ||
175 | config.Set("enable_adaptive_throttles", true); | ||
176 | TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene, ics); | ||
177 | |||
178 | ScenePresence sp | ||
179 | = ClientStackHelpers.AddChildClient( | ||
180 | scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); | ||
181 | |||
182 | LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient; | ||
183 | |||
184 | udpServer.Throttle.DebugLevel = 1; | ||
185 | udpClient.ThrottleDebugLevel = 1; | ||
186 | |||
187 | // Total is 280000 | ||
188 | int resendBytes = 10000; | ||
189 | int landBytes = 20000; | ||
190 | int windBytes = 30000; | ||
191 | int cloudBytes = 40000; | ||
192 | int taskBytes = 50000; | ||
193 | int textureBytes = 60000; | ||
194 | int assetBytes = 70000; | ||
195 | int totalBytes = resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes; | ||
196 | |||
197 | SetThrottles( | ||
198 | udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); | ||
199 | |||
200 | // Ratio of current adaptive drip rate to requested bytes | ||
201 | // XXX: Should hard code this as below so we don't rely on values given by tested code to construct | ||
202 | // expected values. | ||
203 | double commitRatio = (double)udpClient.FlowThrottle.AdjustedDripRate / udpClient.FlowThrottle.TargetDripRate; | ||
204 | |||
205 | AssertThrottles( | ||
206 | udpClient, | ||
207 | LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio, | ||
208 | textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0); | ||
209 | |||
210 | // Test an increase in target throttle | ||
211 | udpClient.FlowThrottle.AcknowledgePackets(35000); | ||
212 | commitRatio = 0.2; | ||
213 | |||
214 | AssertThrottles( | ||
215 | udpClient, | ||
216 | resendBytes * commitRatio, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio, | ||
217 | textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0); | ||
218 | |||
219 | // Test a decrease in target throttle | ||
220 | udpClient.FlowThrottle.ExpirePackets(1); | ||
221 | commitRatio = 0.1; | ||
222 | |||
223 | AssertThrottles( | ||
224 | udpClient, | ||
225 | LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio, | ||
226 | textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0); | ||
227 | } | ||
228 | |||
229 | /// <summary> | ||
230 | /// Test throttle setttings where max client throttle has been limited server side. | ||
231 | /// </summary> | ||
232 | [Test] | ||
233 | public void TestSingleClientThrottleRegionLimited() | ||
234 | { | ||
235 | TestHelpers.InMethod(); | ||
236 | // TestHelpers.EnableLogging(); | ||
237 | |||
238 | int resendBytes = 6000; | ||
239 | int landBytes = 8000; | ||
240 | int windBytes = 10000; | ||
241 | int cloudBytes = 12000; | ||
242 | int taskBytes = 14000; | ||
243 | int textureBytes = 16000; | ||
244 | int assetBytes = 18000; | ||
245 | int totalBytes | ||
246 | = (int)((resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes) / 2); | ||
247 | |||
248 | Scene scene = new SceneHelpers().SetupScene(); | ||
249 | TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene); | ||
250 | udpServer.Throttle.RequestedDripRate = totalBytes; | ||
251 | |||
252 | ScenePresence sp1 | ||
253 | = ClientStackHelpers.AddChildClient( | ||
254 | scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); | ||
255 | |||
256 | LLUDPClient udpClient1 = ((LLClientView)sp1.ControllingClient).UDPClient; | ||
257 | |||
258 | SetThrottles( | ||
259 | udpClient1, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); | ||
260 | |||
261 | AssertThrottles( | ||
262 | udpClient1, | ||
263 | resendBytes / 2, landBytes / 2, windBytes / 2, cloudBytes / 2, taskBytes / 2, | ||
264 | textureBytes / 2, assetBytes / 2, totalBytes, 0, 0); | ||
265 | |||
266 | // Test: Now add another client | ||
267 | ScenePresence sp2 | ||
268 | = ClientStackHelpers.AddChildClient( | ||
269 | scene, udpServer, TestHelpers.ParseTail(0x10), TestHelpers.ParseTail(0x20), 123457); | ||
270 | |||
271 | LLUDPClient udpClient2 = ((LLClientView)sp2.ControllingClient).UDPClient; | ||
272 | // udpClient.ThrottleDebugLevel = 1; | ||
273 | |||
274 | SetThrottles( | ||
275 | udpClient2, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); | ||
276 | |||
277 | AssertThrottles( | ||
278 | udpClient1, | ||
279 | resendBytes / 4, landBytes / 4, windBytes / 4, cloudBytes / 4, taskBytes / 4, | ||
280 | textureBytes / 4, assetBytes / 4, totalBytes / 2, 0, 0); | ||
281 | |||
282 | AssertThrottles( | ||
283 | udpClient2, | ||
284 | resendBytes / 4, landBytes / 4, windBytes / 4, cloudBytes / 4, taskBytes / 4, | ||
285 | textureBytes / 4, assetBytes / 4, totalBytes / 2, 0, 0); | ||
286 | } | ||
287 | |||
288 | /// <summary> | ||
289 | /// Test throttle setttings where max client throttle has been limited server side. | ||
290 | /// </summary> | ||
291 | [Test] | ||
292 | public void TestClientThrottlePerClientLimited() | ||
293 | { | ||
294 | TestHelpers.InMethod(); | ||
295 | // TestHelpers.EnableLogging(); | ||
296 | |||
297 | int resendBytes = 4000; | ||
298 | int landBytes = 6000; | ||
299 | int windBytes = 8000; | ||
300 | int cloudBytes = 10000; | ||
301 | int taskBytes = 12000; | ||
302 | int textureBytes = 14000; | ||
303 | int assetBytes = 16000; | ||
304 | int totalBytes | ||
305 | = (int)((resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes) / 2); | ||
306 | |||
307 | Scene scene = new SceneHelpers().SetupScene(); | ||
308 | TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene); | ||
309 | udpServer.ThrottleRates.Total = totalBytes; | ||
310 | |||
311 | ScenePresence sp | ||
312 | = ClientStackHelpers.AddChildClient( | ||
313 | scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); | ||
314 | |||
315 | LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient; | ||
316 | // udpClient.ThrottleDebugLevel = 1; | ||
317 | |||
318 | SetThrottles( | ||
319 | udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); | ||
320 | |||
321 | AssertThrottles( | ||
322 | udpClient, | ||
323 | resendBytes / 2, landBytes / 2, windBytes / 2, cloudBytes / 2, taskBytes / 2, | ||
324 | textureBytes / 2, assetBytes / 2, totalBytes, 0, totalBytes); | ||
325 | } | ||
326 | |||
327 | [Test] | ||
328 | public void TestClientThrottlePerClientAndRegionLimited() | ||
329 | { | ||
330 | TestHelpers.InMethod(); | ||
331 | //TestHelpers.EnableLogging(); | ||
332 | |||
333 | int resendBytes = 4000; | ||
334 | int landBytes = 6000; | ||
335 | int windBytes = 8000; | ||
336 | int cloudBytes = 10000; | ||
337 | int taskBytes = 12000; | ||
338 | int textureBytes = 14000; | ||
339 | int assetBytes = 16000; | ||
340 | |||
341 | // current total 70000 | ||
342 | int totalBytes = resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes; | ||
343 | |||
344 | Scene scene = new SceneHelpers().SetupScene(); | ||
345 | TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene); | ||
346 | udpServer.ThrottleRates.Total = (int)(totalBytes * 1.1); | ||
347 | udpServer.Throttle.RequestedDripRate = (int)(totalBytes * 1.5); | ||
348 | |||
349 | ScenePresence sp1 | ||
350 | = ClientStackHelpers.AddChildClient( | ||
351 | scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); | ||
352 | |||
353 | LLUDPClient udpClient1 = ((LLClientView)sp1.ControllingClient).UDPClient; | ||
354 | udpClient1.ThrottleDebugLevel = 1; | ||
355 | |||
356 | SetThrottles( | ||
357 | udpClient1, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); | ||
358 | |||
359 | AssertThrottles( | ||
360 | udpClient1, | ||
361 | resendBytes, landBytes, windBytes, cloudBytes, taskBytes, | ||
362 | textureBytes, assetBytes, totalBytes, 0, totalBytes * 1.1); | ||
363 | |||
364 | // Now add another client | ||
365 | ScenePresence sp2 | ||
366 | = ClientStackHelpers.AddChildClient( | ||
367 | scene, udpServer, TestHelpers.ParseTail(0x10), TestHelpers.ParseTail(0x20), 123457); | ||
368 | |||
369 | LLUDPClient udpClient2 = ((LLClientView)sp2.ControllingClient).UDPClient; | ||
370 | udpClient2.ThrottleDebugLevel = 1; | ||
371 | |||
372 | SetThrottles( | ||
373 | udpClient2, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); | ||
374 | |||
375 | AssertThrottles( | ||
376 | udpClient1, | ||
377 | resendBytes * 0.75, landBytes * 0.75, windBytes * 0.75, cloudBytes * 0.75, taskBytes * 0.75, | ||
378 | textureBytes * 0.75, assetBytes * 0.75, totalBytes * 0.75, 0, totalBytes * 1.1); | ||
379 | |||
380 | AssertThrottles( | ||
381 | udpClient2, | ||
382 | resendBytes * 0.75, landBytes * 0.75, windBytes * 0.75, cloudBytes * 0.75, taskBytes * 0.75, | ||
383 | textureBytes * 0.75, assetBytes * 0.75, totalBytes * 0.75, 0, totalBytes * 1.1); | ||
384 | } | ||
385 | |||
386 | private void AssertThrottles( | ||
387 | LLUDPClient udpClient, | ||
388 | double resendBytes, double landBytes, double windBytes, double cloudBytes, double taskBytes, double textureBytes, double assetBytes, | ||
389 | double totalBytes, double targetBytes, double maxBytes) | ||
390 | { | ||
391 | ClientInfo ci = udpClient.GetClientInfo(); | ||
392 | |||
393 | // Console.WriteLine( | ||
394 | // "Resend={0}, Land={1}, Wind={2}, Cloud={3}, Task={4}, Texture={5}, Asset={6}, TOTAL = {7}", | ||
395 | // ci.resendThrottle, ci.landThrottle, ci.windThrottle, ci.cloudThrottle, ci.taskThrottle, ci.textureThrottle, ci.assetThrottle, ci.totalThrottle); | ||
396 | |||
397 | Assert.AreEqual((int)resendBytes, ci.resendThrottle, "Resend"); | ||
398 | Assert.AreEqual((int)landBytes, ci.landThrottle, "Land"); | ||
399 | Assert.AreEqual((int)windBytes, ci.windThrottle, "Wind"); | ||
400 | Assert.AreEqual((int)cloudBytes, ci.cloudThrottle, "Cloud"); | ||
401 | Assert.AreEqual((int)taskBytes, ci.taskThrottle, "Task"); | ||
402 | Assert.AreEqual((int)textureBytes, ci.textureThrottle, "Texture"); | ||
403 | Assert.AreEqual((int)assetBytes, ci.assetThrottle, "Asset"); | ||
404 | Assert.AreEqual((int)totalBytes, ci.totalThrottle, "Total"); | ||
405 | Assert.AreEqual((int)targetBytes, ci.targetThrottle, "Target"); | ||
406 | Assert.AreEqual((int)maxBytes, ci.maxThrottle, "Max"); | ||
407 | } | ||
408 | |||
409 | private void SetThrottles( | ||
410 | LLUDPClient udpClient, int resendBytes, int landBytes, int windBytes, int cloudBytes, int taskBytes, int textureBytes, int assetBytes) | ||
411 | { | ||
412 | byte[] throttles = new byte[28]; | ||
413 | |||
414 | Array.Copy(BitConverter.GetBytes((float)resendBytes * 8), 0, throttles, 0, 4); | ||
415 | Array.Copy(BitConverter.GetBytes((float)landBytes * 8), 0, throttles, 4, 4); | ||
416 | Array.Copy(BitConverter.GetBytes((float)windBytes * 8), 0, throttles, 8, 4); | ||
417 | Array.Copy(BitConverter.GetBytes((float)cloudBytes * 8), 0, throttles, 12, 4); | ||
418 | Array.Copy(BitConverter.GetBytes((float)taskBytes * 8), 0, throttles, 16, 4); | ||
419 | Array.Copy(BitConverter.GetBytes((float)textureBytes * 8), 0, throttles, 20, 4); | ||
420 | Array.Copy(BitConverter.GetBytes((float)assetBytes * 8), 0, throttles, 24, 4); | ||
421 | |||
422 | udpClient.SetThrottles(throttles); | ||
423 | } | ||
424 | } | ||
425 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs index e5bae6e..dd15cc7 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs | |||
@@ -72,6 +72,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
72 | { | 72 | { |
73 | IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"]; | 73 | IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"]; |
74 | 74 | ||
75 | // Current default total is 66750 | ||
75 | Resend = throttleConfig.GetInt("resend_default", 6625); | 76 | Resend = throttleConfig.GetInt("resend_default", 6625); |
76 | Land = throttleConfig.GetInt("land_default", 9125); | 77 | Land = throttleConfig.GetInt("land_default", 9125); |
77 | Wind = throttleConfig.GetInt("wind_default", 1750); | 78 | Wind = throttleConfig.GetInt("wind_default", 1750); |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs index 658d9bb..d215595 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs | |||
@@ -42,9 +42,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
42 | public class TokenBucket | 42 | public class TokenBucket |
43 | { | 43 | { |
44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
45 | private static Int32 m_counter = 0; | ||
46 | |||
47 | private LLUDPClient m_client; | ||
48 | 45 | ||
49 | public string Identifier { get; private set; } | 46 | public string Identifier { get; private set; } |
50 | 47 | ||
@@ -79,20 +76,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
79 | /// Map of children buckets and their requested maximum burst rate | 76 | /// Map of children buckets and their requested maximum burst rate |
80 | /// </summary> | 77 | /// </summary> |
81 | protected Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>(); | 78 | protected Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>(); |
82 | |||
83 | #region Properties | ||
84 | 79 | ||
85 | /// <summary> | 80 | /// <summary> |
86 | /// The parent bucket of this bucket, or null if this bucket has no | 81 | /// The parent bucket of this bucket, or null if this bucket has no |
87 | /// parent. The parent bucket will limit the aggregate bandwidth of all | 82 | /// parent. The parent bucket will limit the aggregate bandwidth of all |
88 | /// of its children buckets | 83 | /// of its children buckets |
89 | /// </summary> | 84 | /// </summary> |
90 | protected TokenBucket m_parent; | 85 | public TokenBucket Parent { get; protected set; } |
91 | public TokenBucket Parent | ||
92 | { | ||
93 | get { return m_parent; } | ||
94 | set { m_parent = value; } | ||
95 | } | ||
96 | 86 | ||
97 | /// <summary> | 87 | /// <summary> |
98 | /// Maximum burst rate in bytes per second. This is the maximum number | 88 | /// Maximum burst rate in bytes per second. This is the maximum number |
@@ -118,53 +108,85 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
118 | } | 108 | } |
119 | 109 | ||
120 | /// <summary> | 110 | /// <summary> |
121 | /// The speed limit of this bucket in bytes per second. This is the | 111 | /// The requested drip rate for this particular bucket. |
122 | /// number of tokens that are added to the bucket per quantum | ||
123 | /// </summary> | 112 | /// </summary> |
124 | /// <remarks>Tokens are added to the bucket any time | 113 | /// <remarks> |
114 | /// 0 then TotalDripRequest is used instead. | ||
115 | /// Can never be above MaxDripRate. | ||
116 | /// Tokens are added to the bucket at any time | ||
125 | /// <seealso cref="RemoveTokens"/> is called, at the granularity of | 117 | /// <seealso cref="RemoveTokens"/> is called, at the granularity of |
126 | /// the system tick interval (typically around 15-22ms)</remarks> | 118 | /// the system tick interval (typically around 15-22ms) |
127 | protected Int64 m_dripRate; | 119 | /// FIXME: It is extremely confusing to be able to set a RequestedDripRate of 0 and then receive a positive |
120 | /// number on get if TotalDripRequest is sent. This also stops us being able to retrieve the fact that | ||
121 | /// RequestedDripRate is set to 0. Really, this should always return m_dripRate and then we can get | ||
122 | /// (m_dripRate == 0 ? TotalDripRequest : m_dripRate) on some other properties. | ||
123 | /// </remarks> | ||
128 | public virtual Int64 RequestedDripRate | 124 | public virtual Int64 RequestedDripRate |
129 | { | 125 | { |
130 | get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); } | 126 | get { return (m_dripRate == 0 ? TotalDripRequest : m_dripRate); } |
131 | set { | 127 | set |
132 | m_dripRate = (value < 0 ? 0 : value); | 128 | { |
129 | if (value <= 0) | ||
130 | m_dripRate = 0; | ||
131 | else if (MaxDripRate > 0 && value > MaxDripRate) | ||
132 | m_dripRate = MaxDripRate; | ||
133 | else | ||
134 | m_dripRate = value; | ||
135 | |||
133 | m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); | 136 | m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); |
134 | m_totalDripRequest = m_dripRate; | 137 | |
135 | if (m_parent != null) | 138 | if (Parent != null) |
136 | m_parent.RegisterRequest(this,m_dripRate); | 139 | Parent.RegisterRequest(this, m_dripRate); |
137 | } | 140 | } |
138 | } | 141 | } |
139 | 142 | ||
143 | /// <summary> | ||
144 | /// Gets the drip rate. | ||
145 | /// </summary> | ||
146 | /// <value> | ||
147 | /// DripRate can never be above max drip rate or below min drip rate. | ||
148 | /// If we are a child bucket then the drip rate return is modifed by the total load on the capacity of the | ||
149 | /// parent bucket. | ||
150 | /// </value> | ||
140 | public virtual Int64 DripRate | 151 | public virtual Int64 DripRate |
141 | { | 152 | { |
142 | get { | 153 | get |
143 | if (m_parent == null) | 154 | { |
144 | return Math.Min(RequestedDripRate,TotalDripRequest); | 155 | double rate; |
145 | 156 | ||
146 | double rate = (double)RequestedDripRate * m_parent.DripRateModifier(); | 157 | // FIXME: This doesn't properly work if we have a parent and children and a requested drip rate set |
158 | // on ourselves which is not equal to the child drip rates. | ||
159 | if (Parent == null) | ||
160 | { | ||
161 | if (TotalDripRequest > 0) | ||
162 | rate = Math.Min(RequestedDripRate, TotalDripRequest); | ||
163 | else | ||
164 | rate = RequestedDripRate; | ||
165 | } | ||
166 | else | ||
167 | { | ||
168 | rate = (double)RequestedDripRate * Parent.DripRateModifier(); | ||
169 | } | ||
170 | |||
147 | if (rate < m_minimumDripRate) | 171 | if (rate < m_minimumDripRate) |
148 | rate = m_minimumDripRate; | 172 | rate = m_minimumDripRate; |
173 | else if (MaxDripRate > 0 && rate > MaxDripRate) | ||
174 | rate = MaxDripRate; | ||
149 | 175 | ||
150 | return (Int64)rate; | 176 | return (Int64)rate; |
151 | } | 177 | } |
152 | } | 178 | } |
179 | protected Int64 m_dripRate; | ||
180 | |||
181 | // <summary> | ||
182 | // The maximum rate for flow control. Drip rate can never be greater than this. | ||
183 | // </summary> | ||
184 | public Int64 MaxDripRate { get; set; } | ||
153 | 185 | ||
154 | /// <summary> | 186 | /// <summary> |
155 | /// The current total of the requested maximum burst rates of | 187 | /// The current total of the requested maximum burst rates of children buckets. |
156 | /// this bucket's children buckets. | ||
157 | /// </summary> | 188 | /// </summary> |
158 | protected Int64 m_totalDripRequest; | 189 | public Int64 TotalDripRequest { get; protected set; } |
159 | public Int64 TotalDripRequest | ||
160 | { | ||
161 | get { return m_totalDripRequest; } | ||
162 | set { m_totalDripRequest = value; } | ||
163 | } | ||
164 | |||
165 | #endregion Properties | ||
166 | |||
167 | #region Constructor | ||
168 | 190 | ||
169 | /// <summary> | 191 | /// <summary> |
170 | /// Default constructor | 192 | /// Default constructor |
@@ -172,21 +194,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
172 | /// <param name="identifier">Identifier for this token bucket</param> | 194 | /// <param name="identifier">Identifier for this token bucket</param> |
173 | /// <param name="parent">Parent bucket if this is a child bucket, or | 195 | /// <param name="parent">Parent bucket if this is a child bucket, or |
174 | /// null if this is a root bucket</param> | 196 | /// null if this is a root bucket</param> |
175 | /// <param name="dripRate">Rate that the bucket fills, in bytes per | 197 | /// <param name="requestedDripRate"> |
176 | /// second. If zero, the bucket always remains full</param> | 198 | /// Requested rate that the bucket fills, in bytes per |
177 | public TokenBucket(string identifier, TokenBucket parent, Int64 dripRate) | 199 | /// second. If zero, the bucket always remains full. |
200 | /// </param> | ||
201 | public TokenBucket(string identifier, TokenBucket parent, Int64 requestedDripRate, Int64 maxDripRate) | ||
178 | { | 202 | { |
179 | Identifier = identifier; | 203 | Identifier = identifier; |
180 | 204 | ||
181 | Parent = parent; | 205 | Parent = parent; |
182 | RequestedDripRate = dripRate; | 206 | RequestedDripRate = requestedDripRate; |
183 | // TotalDripRequest = dripRate; // this will be overwritten when a child node registers | 207 | MaxDripRate = maxDripRate; |
184 | // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst); | ||
185 | m_lastDrip = Util.EnvironmentTickCount(); | 208 | m_lastDrip = Util.EnvironmentTickCount(); |
186 | } | 209 | } |
187 | 210 | ||
188 | #endregion Constructor | ||
189 | |||
190 | /// <summary> | 211 | /// <summary> |
191 | /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning | 212 | /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning |
192 | /// no modification if the requested bandwidth is less than the | 213 | /// no modification if the requested bandwidth is less than the |
@@ -197,7 +218,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
197 | protected double DripRateModifier() | 218 | protected double DripRateModifier() |
198 | { | 219 | { |
199 | Int64 driprate = DripRate; | 220 | Int64 driprate = DripRate; |
200 | return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; | 221 | double modifier = driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; |
222 | |||
223 | // if (DebugLevel > 0) | ||
224 | // m_log.DebugFormat( | ||
225 | // "[TOKEN BUCKET]: Returning drip modifier {0}/{1} = {2} from {3}", | ||
226 | // driprate, TotalDripRequest, modifier, Identifier); | ||
227 | |||
228 | return modifier; | ||
201 | } | 229 | } |
202 | 230 | ||
203 | /// <summary> | 231 | /// <summary> |
@@ -219,16 +247,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
219 | lock (m_children) | 247 | lock (m_children) |
220 | { | 248 | { |
221 | m_children[child] = request; | 249 | m_children[child] = request; |
222 | // m_totalDripRequest = m_children.Values.Sum(); | ||
223 | 250 | ||
224 | m_totalDripRequest = 0; | 251 | TotalDripRequest = 0; |
225 | foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) | 252 | foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) |
226 | m_totalDripRequest += cref.Value; | 253 | TotalDripRequest += cref.Value; |
227 | } | 254 | } |
228 | 255 | ||
229 | // Pass the new values up to the parent | 256 | // Pass the new values up to the parent |
230 | if (m_parent != null) | 257 | if (Parent != null) |
231 | m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); | 258 | { |
259 | Int64 effectiveDripRate; | ||
260 | |||
261 | if (RequestedDripRate > 0) | ||
262 | effectiveDripRate = Math.Min(RequestedDripRate, TotalDripRequest); | ||
263 | else | ||
264 | effectiveDripRate = TotalDripRequest; | ||
265 | |||
266 | Parent.RegisterRequest(this, effectiveDripRate); | ||
267 | } | ||
232 | } | 268 | } |
233 | 269 | ||
234 | /// <summary> | 270 | /// <summary> |
@@ -240,17 +276,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
240 | lock (m_children) | 276 | lock (m_children) |
241 | { | 277 | { |
242 | m_children.Remove(child); | 278 | m_children.Remove(child); |
243 | // m_totalDripRequest = m_children.Values.Sum(); | ||
244 | 279 | ||
245 | m_totalDripRequest = 0; | 280 | TotalDripRequest = 0; |
246 | foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) | 281 | foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) |
247 | m_totalDripRequest += cref.Value; | 282 | TotalDripRequest += cref.Value; |
248 | } | 283 | } |
249 | |||
250 | 284 | ||
251 | // Pass the new values up to the parent | 285 | // Pass the new values up to the parent |
252 | if (m_parent != null) | 286 | if (Parent != null) |
253 | m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); | 287 | Parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); |
254 | } | 288 | } |
255 | 289 | ||
256 | /// <summary> | 290 | /// <summary> |
@@ -323,64 +357,66 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
323 | 357 | ||
324 | public class AdaptiveTokenBucket : TokenBucket | 358 | public class AdaptiveTokenBucket : TokenBucket |
325 | { | 359 | { |
326 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 360 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
361 | |||
362 | public bool AdaptiveEnabled { get; set; } | ||
327 | 363 | ||
328 | /// <summary> | 364 | /// <summary> |
329 | /// The minimum rate for flow control. Minimum drip rate is one | 365 | /// Target drip rate for this bucket. |
330 | /// packet per second. Open the throttle to 15 packets per second | ||
331 | /// or about 160kbps. | ||
332 | /// </summary> | 366 | /// </summary> |
333 | protected const Int64 m_minimumFlow = m_minimumDripRate * 15; | 367 | /// <remarks>Usually set by the client. If adaptive is enabled then throttles will increase until we reach this.</remarks> |
334 | 368 | public Int64 TargetDripRate | |
335 | // <summary> | 369 | { |
336 | // The maximum rate for flow control. Drip rate can never be | 370 | get { return m_targetDripRate; } |
337 | // greater than this. | 371 | set |
338 | // </summary> | 372 | { |
339 | protected Int64 m_maxDripRate = 0; | 373 | m_targetDripRate = Math.Max(value, m_minimumFlow); |
340 | public Int64 MaxDripRate | 374 | } |
341 | { | ||
342 | get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); } | ||
343 | protected set { m_maxDripRate = (value == 0 ? 0 : Math.Max(value,m_minimumFlow)); } | ||
344 | } | 375 | } |
376 | protected Int64 m_targetDripRate; | ||
345 | 377 | ||
346 | public bool Enabled { get; private set; } | ||
347 | |||
348 | // <summary> | 378 | // <summary> |
349 | // | 379 | // Adjust drip rate in response to network conditions. |
350 | // </summary> | 380 | // </summary> |
351 | public virtual Int64 AdjustedDripRate | 381 | public virtual Int64 AdjustedDripRate |
352 | { | 382 | { |
353 | get { return m_dripRate; } | 383 | get { return m_dripRate; } |
354 | set { | 384 | set |
355 | m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value,m_minimumFlow,MaxDripRate); | 385 | { |
386 | m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value, m_minimumFlow, TargetDripRate); | ||
356 | m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); | 387 | m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); |
357 | if (m_parent != null) | 388 | |
358 | m_parent.RegisterRequest(this,m_dripRate); | 389 | if (Parent != null) |
390 | Parent.RegisterRequest(this, m_dripRate); | ||
359 | } | 391 | } |
360 | } | 392 | } |
393 | |||
394 | /// <summary> | ||
395 | /// The minimum rate for flow control. Minimum drip rate is one | ||
396 | /// packet per second. Open the throttle to 15 packets per second | ||
397 | /// or about 160kbps. | ||
398 | /// </summary> | ||
399 | protected const Int64 m_minimumFlow = m_minimumDripRate * 15; | ||
361 | 400 | ||
362 | // <summary> | 401 | public AdaptiveTokenBucket(string identifier, TokenBucket parent, Int64 requestedDripRate, Int64 maxDripRate, bool enabled) |
363 | // | 402 | : base(identifier, parent, requestedDripRate, maxDripRate) |
364 | // </summary> | ||
365 | public AdaptiveTokenBucket(string identifier, TokenBucket parent, Int64 maxDripRate, bool enabled) | ||
366 | : base(identifier, parent, maxDripRate) | ||
367 | { | 403 | { |
368 | Enabled = enabled; | 404 | AdaptiveEnabled = enabled; |
369 | 405 | ||
370 | if (Enabled) | 406 | if (AdaptiveEnabled) |
371 | { | 407 | { |
372 | // m_log.DebugFormat("[TOKENBUCKET]: Adaptive throttle enabled"); | 408 | // m_log.DebugFormat("[TOKENBUCKET]: Adaptive throttle enabled"); |
373 | MaxDripRate = maxDripRate; | 409 | TargetDripRate = m_minimumFlow; |
374 | AdjustedDripRate = m_minimumFlow; | 410 | AdjustedDripRate = m_minimumFlow; |
375 | } | 411 | } |
376 | } | 412 | } |
377 | 413 | ||
378 | // <summary> | 414 | // <summary> |
379 | // | 415 | // Reliable packets sent to the client for which we never received an ack adjust the drip rate down. |
380 | // </summary> | 416 | // </summary> |
381 | public void ExpirePackets(Int32 count) | 417 | public void ExpirePackets(Int32 count) |
382 | { | 418 | { |
383 | if (Enabled) | 419 | if (AdaptiveEnabled) |
384 | { | 420 | { |
385 | if (DebugLevel > 0) | 421 | if (DebugLevel > 0) |
386 | m_log.WarnFormat( | 422 | m_log.WarnFormat( |
@@ -392,12 +428,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
392 | } | 428 | } |
393 | 429 | ||
394 | // <summary> | 430 | // <summary> |
395 | // | 431 | // Reliable packets acked by the client adjust the drip rate up. |
396 | // </summary> | 432 | // </summary> |
397 | public void AcknowledgePackets(Int32 count) | 433 | public void AcknowledgePackets(Int32 count) |
398 | { | 434 | { |
399 | if (Enabled) | 435 | if (AdaptiveEnabled) |
400 | AdjustedDripRate = AdjustedDripRate + count; | 436 | AdjustedDripRate = AdjustedDripRate + count; |
401 | } | 437 | } |
402 | } | 438 | } |
403 | } | 439 | } \ No newline at end of file |